maid 0.2.1 → 0.2.2.beta.1

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.
@@ -1,3 +1,4 @@
1
1
  rvm:
2
2
  - 1.8.7
3
3
  - 1.9.3
4
+ - 2.0.0
data/ChangeLog CHANGED
@@ -1,3 +1,12 @@
1
+ maid (0.2.2.beta.1) unstable; urgency=low
2
+
3
+ * Added better documentation (Closes: #91)
4
+ * Safely escape shell commands (Closes: #70)
5
+ * Made gem version dependencies less strict
6
+ * Started experimental Ruby 2.0 support
7
+
8
+ -- Benjamin Oakes <hello@benjaminoakes.com> Sun, 17 Feb 2013 00:00:00 +0000
9
+
1
10
  maid (0.2.1) stable; urgency=low
2
11
 
3
12
  * Fix YARD generation for http://rubydoc.info/. (Otherwise identical to
data/Guardfile CHANGED
@@ -1,6 +1,4 @@
1
- # A sample Guardfile
2
1
  # More info at https://github.com/guard/guard#readme
3
-
4
2
  guard 'rspec' do
5
3
  watch(%r{^spec/.+_spec\.rb$})
6
4
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{ m[1] }_spec.rb" }
data/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  Be lazy! Let Maid clean up after you, based on rules you define.
4
4
 
5
- [Installation](https://github.com/benjaminoakes/maid#installation)
6
- | [Tutorial](https://github.com/benjaminoakes/maid#tutorial)
5
+ [Installation](#installation)
6
+ | [Tutorial](#tutorial)
7
7
  | [Example](https://github.com/benjaminoakes/maid-example)
8
8
  | [User Community](https://github.com/benjaminoakes/maid/wiki)
9
9
  | [Documentation][]
@@ -1,4 +1,5 @@
1
1
  require 'deprecated'
2
+ require 'escape'
2
3
  Deprecated.set_action(:warn)
3
4
 
4
5
  # Must be in this order:
@@ -12,6 +12,7 @@ require 'time'
12
12
  # Some methods are not available on all platforms. An `ArgumentError` is raised when a command is not available. See
13
13
  # tags such as: [Mac OS X]
14
14
  module Maid::Tools
15
+ # For showing deprecation notices
15
16
  include Deprecated
16
17
 
17
18
  # Move from `sources` to `destination`
@@ -35,10 +36,10 @@ module Maid::Tools
35
36
  target = File.join(destination, File.basename(source))
36
37
 
37
38
  unless File.exist?(target)
38
- log("mv #{ source.inspect } #{ destination.inspect }")
39
+ log("mv #{ sh_escape(source) } #{ sh_escape(destination) }")
39
40
  FileUtils.mv(source, destination, @file_options)
40
41
  else
41
- warn("skipping #{ source.inspect } because #{ target.inspect } already exists")
42
+ warn("skipping #{ sh_escape(source) } because #{ sh_escape(target) } already exists")
42
43
  end
43
44
  end
44
45
  end
@@ -136,7 +137,7 @@ module Maid::Tools
136
137
  expand_all(paths).each do |path|
137
138
  options = @file_options.merge(options)
138
139
 
139
- log("Removing #{ path.inspect }")
140
+ log("Removing #{ sh_escape(path) }")
140
141
  FileUtils.rm_r(path, options)
141
142
  end
142
143
  end
@@ -164,6 +165,10 @@ module Maid::Tools
164
165
  # dir(%w(~/Downloads/*.zip ~/Dropbox/*.zip))
165
166
  # dir('~/{Downloads,Dropbox}/*.zip')
166
167
  #
168
+ # Recursing into subdirectories (see also: `find`):
169
+ #
170
+ # dir('~/Music/**/*.m4a')
171
+ #
167
172
  def dir(globs)
168
173
  expand_all(globs).
169
174
  map { |glob| Dir.glob(glob) }.
@@ -192,7 +197,7 @@ module Maid::Tools
192
197
  # move('~/Downloads/Pink Floyd*.mp3', mkdir('~/Music/Pink Floyd/'))
193
198
  def mkdir(path, options = {})
194
199
  path = expand(path)
195
- log("mkdir -p #{ path.inspect }")
200
+ log("mkdir -p #{ sh_escape(path) }")
196
201
  FileUtils.mkdir_p(path, @file_options.merge(options))
197
202
  path
198
203
  end
@@ -239,7 +244,7 @@ module Maid::Tools
239
244
  #
240
245
  # locate('foo.zip') # => ['/a/foo.zip', '/b/foo.zip']
241
246
  def locate(name)
242
- cmd("mdfind -name #{ name.inspect }").split("\n")
247
+ cmd("mdfind -name #{ sh_escape(name) }").split("\n")
243
248
  end
244
249
 
245
250
  # [Mac OS X] Use Spotlight metadata to determine the site from which a file was downloaded.
@@ -248,7 +253,7 @@ module Maid::Tools
248
253
  #
249
254
  # downloaded_from('foo.zip') # => ['http://www.site.com/foo.zip', 'http://www.site.com/']
250
255
  def downloaded_from(path)
251
- raw = cmd("mdls -raw -name kMDItemWhereFroms #{ path.inspect }")
256
+ raw = cmd("mdls -raw -name kMDItemWhereFroms #{ sh_escape(path) }")
252
257
  clean = raw[1, raw.length - 2]
253
258
  clean.split(/,\s+/).map { |s| t = s.strip; t[1, t.length - 2] }
254
259
  end
@@ -259,7 +264,7 @@ module Maid::Tools
259
264
  #
260
265
  # duration_s('foo.mp3') # => 235.705
261
266
  def duration_s(path)
262
- cmd("mdls -raw -name kMDItemDurationSeconds #{ path.inspect }").to_f
267
+ cmd("mdls -raw -name kMDItemDurationSeconds #{ sh_escape(path) }").to_f
263
268
  end
264
269
 
265
270
  # List the contents of a zip file.
@@ -268,7 +273,7 @@ module Maid::Tools
268
273
  #
269
274
  # zipfile_contents('foo.zip') # => ['foo/foo.exe', 'foo/README.txt']
270
275
  def zipfile_contents(path)
271
- raw = cmd("unzip -Z1 #{ path.inspect }")
276
+ raw = cmd("unzip -Z1 #{ sh_escape(path) }")
272
277
  raw.split("\n")
273
278
  end
274
279
 
@@ -280,7 +285,7 @@ module Maid::Tools
280
285
  #
281
286
  # disk_usage('foo.zip') # => 136
282
287
  def disk_usage(path)
283
- raw = cmd("du -s #{ path.inspect }")
288
+ raw = cmd("du -s #{ sh_escape(path) }")
284
289
  # FIXME: This reports in kilobytes, but should probably report in bytes.
285
290
  usage_kb = raw.split(/\s+/).first.to_i
286
291
 
@@ -345,8 +350,8 @@ module Maid::Tools
345
350
  # git_piston('~/code/projectname')
346
351
  def git_piston(path)
347
352
  full_path = expand(path)
348
- stdout = cmd("cd #{full_path.inspect} && git pull && git push 2>&1")
349
- log("Fired git piston on #{full_path.inspect}. STDOUT:\n\n#{stdout}")
353
+ stdout = cmd("cd #{ sh_escape(full_path) } && git pull && git push 2>&1")
354
+ log("Fired git piston on #{ sh_escape(full_path) }. STDOUT:\n\n#{ stdout }")
350
355
  end
351
356
 
352
357
  deprecated :git_piston, 'SparkleShare (http://sparkleshare.org/)'
@@ -394,16 +399,20 @@ module Maid::Tools
394
399
  ops << '-n' if @file_options[:noop]
395
400
 
396
401
  Array(options[:exclude]).each do |path|
397
- ops << "--exclude=#{ path.inspect }"
402
+ ops << "--exclude=#{ sh_escape(path) }"
398
403
  end
399
404
 
400
405
  ops << '--delete' if options[:delete]
401
- stdout = cmd("rsync #{ ops.join(' ') } #{ from.inspect } #{ to.inspect } 2>&1")
402
- log("Fired sync from #{ from.inspect } to #{ to.inspect }. STDOUT:\n\n#{ stdout }")
406
+ stdout = cmd("rsync #{ ops.join(' ') } #{ sh_escape(from) } #{ sh_escape(to) } 2>&1")
407
+ log("Fired sync from #{ sh_escape(from) } to #{ sh_escape(to) }. STDOUT:\n\n#{ stdout }")
403
408
  end
404
409
 
405
410
  private
406
411
 
412
+ def sh_escape(array)
413
+ Escape.shell_command(Array(array))
414
+ end
415
+
407
416
  def log(message)
408
417
  @logger.info(message)
409
418
  end
@@ -1,3 +1,3 @@
1
1
  module Maid
2
- VERSION = '0.2.1'
2
+ VERSION = '0.2.2.beta.1'
3
3
  end
@@ -16,26 +16,29 @@ Gem::Specification.new do |s|
16
16
 
17
17
  s.rubyforge_project = 'maid'
18
18
 
19
- s.add_dependency('thor', '~> 0.16.0')
20
- s.add_dependency('deprecated', '~> 3.0.1')
21
- s.add_dependency('ohai', '~> 6.14.0')
22
- s.add_dependency('xdg', '~> 2.2.3')
23
- s.add_development_dependency('fakefs', '~> 0.4.1')
24
- s.add_development_dependency('guard', '~> 1.5.4')
25
- s.add_development_dependency('guard-rspec', '~> 2.3.0')
26
- s.add_development_dependency('rb-readline', '~> 0.4.2') # To get guard file change detection working properly
27
- s.add_development_dependency('rake', '~> 10.0.2')
19
+ # Strategy: if possible, use ranges (so there are fewer chances of version conflicts)
20
+ s.add_dependency('escape', '>= 0.0.1', '< 0.1.0') # Used for better Ruby 1.8.7 support
21
+ s.add_dependency('thor', '>= 0.14.0', '< 0.18.0')
22
+ s.add_dependency('deprecated', '~> 3.0.0')
23
+ s.add_dependency('ohai', '>= 6.14.0', '< 6.17.0')
24
+ s.add_dependency('xdg', '~> 2.2.3') # previous versions had bugs
25
+
26
+ # Strategy: specific versions (since they're just for development)
27
+ s.add_development_dependency('fakefs', '~> 0.4.2')
28
+ s.add_development_dependency('guard', '~> 1.6.2')
29
+ s.add_development_dependency('guard-rspec', '~> 2.4.0')
30
+ s.add_development_dependency('rake', '~> 10.0.3')
28
31
  s.add_development_dependency('redcarpet', '~> 2.2.2') # Soft dependency of `yard`
29
32
  s.add_development_dependency('rspec', '~> 2.12.0')
30
- s.add_development_dependency('timecop', '~> 0.5.3')
31
- s.add_development_dependency('yard', '~> 0.8.3')
33
+ s.add_development_dependency('timecop', '~> 0.5.9.1')
34
+ s.add_development_dependency('yard', '~> 0.8.4')
32
35
 
33
36
  # In Vagrant, polling won't cross over the OS boundary if you develop in the host OS but run your tests in the
34
37
  # guest. One way around this is to force polling instead:
35
38
  #
36
39
  # bundle exec guard --force-polling
37
40
  #
38
- s.add_development_dependency('rb-inotify', '~> 0.8.8')
41
+ s.add_development_dependency('rb-inotify', '~> 0.9.0')
39
42
  s.add_development_dependency('rb-fsevent', '~> 0.9.2')
40
43
 
41
44
  s.files = `git ls-files`.split("\n")
@@ -196,6 +196,10 @@ module Maid
196
196
  it 'lists files in directories when using regexp-like glob patterns' do
197
197
  @maid.dir('~/{Desktop,Downloads}/*.zip').should == [@other_file, @file]
198
198
  end
199
+
200
+ it 'lists files in directories when using recursive glob patterns' do
201
+ @maid.dir('~/**/*.zip').should == [@other_file, @file]
202
+ end
199
203
  end
200
204
  end
201
205
 
@@ -334,7 +338,7 @@ module Maid
334
338
  end
335
339
 
336
340
  it 'should pull and push the given git repository, logging the action' do
337
- @maid.should_receive(:cmd).with(%(cd "#@home/code/projectname" && git pull && git push 2>&1))
341
+ @maid.should_receive(:cmd).with(%(cd #@home/code/projectname && git pull && git push 2>&1))
338
342
  @logger.should_receive(:info)
339
343
  @maid.git_piston('~/code/projectname')
340
344
  end
@@ -347,7 +351,7 @@ module Maid
347
351
  end
348
352
 
349
353
  it 'should sync the expanded paths, retaining backslash' do
350
- @maid.should_receive(:cmd).with(%(rsync -a -u "#@home/Downloads/" "#@home/Reference" 2>&1))
354
+ @maid.should_receive(:cmd).with(%(rsync -a -u #@home/Downloads/ #@home/Reference 2>&1))
351
355
  @maid.sync(@src_dir, @dst_dir)
352
356
  end
353
357
 
@@ -357,25 +361,25 @@ module Maid
357
361
  end
358
362
 
359
363
  it 'should have no options' do
360
- @maid.should_receive(:cmd).with(%(rsync "#@home/Downloads/" "#@home/Reference" 2>&1))
364
+ @maid.should_receive(:cmd).with(%(rsync #@home/Downloads/ #@home/Reference 2>&1))
361
365
  @maid.sync(@src_dir, @dst_dir, :archive => false, :update => false)
362
366
  end
363
367
 
364
368
  it 'should add all options' do
365
- @maid.should_receive(:cmd).with(%(rsync -a -v -u -m --exclude=".git" --delete "#@home/Downloads/" "#@home/Reference" 2>&1))
369
+ @maid.should_receive(:cmd).with(%(rsync -a -v -u -m --exclude=.git --delete #@home/Downloads/ #@home/Reference 2>&1))
366
370
  @maid.sync(@src_dir, @dst_dir, :archive => true, :update => true, :delete => true, :verbose => true, :prune_empty => true, :exclude => '.git')
367
371
  end
368
372
 
369
373
  it 'should add multiple exlcude options' do
370
374
  @maid.
371
375
  should_receive(:cmd).
372
- with(%(rsync -a -u --exclude=".git" --exclude=".rvmrc" "#@home/Downloads/" "#@home/Reference" 2>&1))
376
+ with(%(rsync -a -u --exclude=.git --exclude=.rvmrc #@home/Downloads/ #@home/Reference 2>&1))
373
377
  @maid.sync(@src_dir, @dst_dir, :exclude => ['.git', '.rvmrc'])
374
378
  end
375
379
 
376
380
  it 'should add noop option' do
377
381
  @maid.file_options[:noop] = true
378
- @maid.should_receive(:cmd).with(%(rsync -a -u -n "#@home/Downloads/" "#@home/Reference" 2>&1))
382
+ @maid.should_receive(:cmd).with(%(rsync -a -u -n #@home/Downloads/ #@home/Reference 2>&1))
379
383
  @maid.sync(@src_dir, @dst_dir)
380
384
  end
381
385
  end
metadata CHANGED
@@ -1,52 +1,72 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: maid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
5
- prerelease:
4
+ version: 0.2.2.beta.1
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Benjamin Oakes
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-25 00:00:00.000000000 Z
12
+ date: 2013-02-17 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: escape
16
+ requirement: &7714060 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.0.1
22
+ - - <
23
+ - !ruby/object:Gem::Version
24
+ version: 0.1.0
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: *7714060
14
28
  - !ruby/object:Gem::Dependency
15
29
  name: thor
16
- requirement: &9942340 !ruby/object:Gem::Requirement
30
+ requirement: &7704680 !ruby/object:Gem::Requirement
17
31
  none: false
18
32
  requirements:
19
- - - ~>
33
+ - - ! '>='
34
+ - !ruby/object:Gem::Version
35
+ version: 0.14.0
36
+ - - <
20
37
  - !ruby/object:Gem::Version
21
- version: 0.16.0
38
+ version: 0.18.0
22
39
  type: :runtime
23
40
  prerelease: false
24
- version_requirements: *9942340
41
+ version_requirements: *7704680
25
42
  - !ruby/object:Gem::Dependency
26
43
  name: deprecated
27
- requirement: &10005180 !ruby/object:Gem::Requirement
44
+ requirement: &7703240 !ruby/object:Gem::Requirement
28
45
  none: false
29
46
  requirements:
30
47
  - - ~>
31
48
  - !ruby/object:Gem::Version
32
- version: 3.0.1
49
+ version: 3.0.0
33
50
  type: :runtime
34
51
  prerelease: false
35
- version_requirements: *10005180
52
+ version_requirements: *7703240
36
53
  - !ruby/object:Gem::Dependency
37
54
  name: ohai
38
- requirement: &10003340 !ruby/object:Gem::Requirement
55
+ requirement: &7702440 !ruby/object:Gem::Requirement
39
56
  none: false
40
57
  requirements:
41
- - - ~>
58
+ - - ! '>='
42
59
  - !ruby/object:Gem::Version
43
60
  version: 6.14.0
61
+ - - <
62
+ - !ruby/object:Gem::Version
63
+ version: 6.17.0
44
64
  type: :runtime
45
65
  prerelease: false
46
- version_requirements: *10003340
66
+ version_requirements: *7702440
47
67
  - !ruby/object:Gem::Dependency
48
68
  name: xdg
49
- requirement: &10001860 !ruby/object:Gem::Requirement
69
+ requirement: &7701440 !ruby/object:Gem::Requirement
50
70
  none: false
51
71
  requirements:
52
72
  - - ~>
@@ -54,65 +74,54 @@ dependencies:
54
74
  version: 2.2.3
55
75
  type: :runtime
56
76
  prerelease: false
57
- version_requirements: *10001860
77
+ version_requirements: *7701440
58
78
  - !ruby/object:Gem::Dependency
59
79
  name: fakefs
60
- requirement: &10001120 !ruby/object:Gem::Requirement
80
+ requirement: &7700740 !ruby/object:Gem::Requirement
61
81
  none: false
62
82
  requirements:
63
83
  - - ~>
64
84
  - !ruby/object:Gem::Version
65
- version: 0.4.1
85
+ version: 0.4.2
66
86
  type: :development
67
87
  prerelease: false
68
- version_requirements: *10001120
88
+ version_requirements: *7700740
69
89
  - !ruby/object:Gem::Dependency
70
90
  name: guard
71
- requirement: &10000560 !ruby/object:Gem::Requirement
91
+ requirement: &7700040 !ruby/object:Gem::Requirement
72
92
  none: false
73
93
  requirements:
74
94
  - - ~>
75
95
  - !ruby/object:Gem::Version
76
- version: 1.5.4
96
+ version: 1.6.2
77
97
  type: :development
78
98
  prerelease: false
79
- version_requirements: *10000560
99
+ version_requirements: *7700040
80
100
  - !ruby/object:Gem::Dependency
81
101
  name: guard-rspec
82
- requirement: &9999640 !ruby/object:Gem::Requirement
102
+ requirement: &7699300 !ruby/object:Gem::Requirement
83
103
  none: false
84
104
  requirements:
85
105
  - - ~>
86
106
  - !ruby/object:Gem::Version
87
- version: 2.3.0
107
+ version: 2.4.0
88
108
  type: :development
89
109
  prerelease: false
90
- version_requirements: *9999640
91
- - !ruby/object:Gem::Dependency
92
- name: rb-readline
93
- requirement: &9998740 !ruby/object:Gem::Requirement
94
- none: false
95
- requirements:
96
- - - ~>
97
- - !ruby/object:Gem::Version
98
- version: 0.4.2
99
- type: :development
100
- prerelease: false
101
- version_requirements: *9998740
110
+ version_requirements: *7699300
102
111
  - !ruby/object:Gem::Dependency
103
112
  name: rake
104
- requirement: &10014900 !ruby/object:Gem::Requirement
113
+ requirement: &7698640 !ruby/object:Gem::Requirement
105
114
  none: false
106
115
  requirements:
107
116
  - - ~>
108
117
  - !ruby/object:Gem::Version
109
- version: 10.0.2
118
+ version: 10.0.3
110
119
  type: :development
111
120
  prerelease: false
112
- version_requirements: *10014900
121
+ version_requirements: *7698640
113
122
  - !ruby/object:Gem::Dependency
114
123
  name: redcarpet
115
- requirement: &10014020 !ruby/object:Gem::Requirement
124
+ requirement: &7697940 !ruby/object:Gem::Requirement
116
125
  none: false
117
126
  requirements:
118
127
  - - ~>
@@ -120,10 +129,10 @@ dependencies:
120
129
  version: 2.2.2
121
130
  type: :development
122
131
  prerelease: false
123
- version_requirements: *10014020
132
+ version_requirements: *7697940
124
133
  - !ruby/object:Gem::Dependency
125
134
  name: rspec
126
- requirement: &10012340 !ruby/object:Gem::Requirement
135
+ requirement: &7687280 !ruby/object:Gem::Requirement
127
136
  none: false
128
137
  requirements:
129
138
  - - ~>
@@ -131,43 +140,43 @@ dependencies:
131
140
  version: 2.12.0
132
141
  type: :development
133
142
  prerelease: false
134
- version_requirements: *10012340
143
+ version_requirements: *7687280
135
144
  - !ruby/object:Gem::Dependency
136
145
  name: timecop
137
- requirement: &10011140 !ruby/object:Gem::Requirement
146
+ requirement: &7686480 !ruby/object:Gem::Requirement
138
147
  none: false
139
148
  requirements:
140
149
  - - ~>
141
150
  - !ruby/object:Gem::Version
142
- version: 0.5.3
151
+ version: 0.5.9.1
143
152
  type: :development
144
153
  prerelease: false
145
- version_requirements: *10011140
154
+ version_requirements: *7686480
146
155
  - !ruby/object:Gem::Dependency
147
156
  name: yard
148
- requirement: &10009380 !ruby/object:Gem::Requirement
157
+ requirement: &7685980 !ruby/object:Gem::Requirement
149
158
  none: false
150
159
  requirements:
151
160
  - - ~>
152
161
  - !ruby/object:Gem::Version
153
- version: 0.8.3
162
+ version: 0.8.4
154
163
  type: :development
155
164
  prerelease: false
156
- version_requirements: *10009380
165
+ version_requirements: *7685980
157
166
  - !ruby/object:Gem::Dependency
158
167
  name: rb-inotify
159
- requirement: &10026320 !ruby/object:Gem::Requirement
168
+ requirement: &7685520 !ruby/object:Gem::Requirement
160
169
  none: false
161
170
  requirements:
162
171
  - - ~>
163
172
  - !ruby/object:Gem::Version
164
- version: 0.8.8
173
+ version: 0.9.0
165
174
  type: :development
166
175
  prerelease: false
167
- version_requirements: *10026320
176
+ version_requirements: *7685520
168
177
  - !ruby/object:Gem::Dependency
169
178
  name: rb-fsevent
170
- requirement: &10024260 !ruby/object:Gem::Requirement
179
+ requirement: &7685040 !ruby/object:Gem::Requirement
171
180
  none: false
172
181
  requirements:
173
182
  - - ~>
@@ -175,7 +184,7 @@ dependencies:
175
184
  version: 0.9.2
176
185
  type: :development
177
186
  prerelease: false
178
- version_requirements: *10024260
187
+ version_requirements: *7685040
179
188
  description: Be lazy. Let Maid clean up after you, based on rules you define. Think
180
189
  of it as "Hazel for hackers".
181
190
  email:
@@ -247,9 +256,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
247
256
  required_rubygems_version: !ruby/object:Gem::Requirement
248
257
  none: false
249
258
  requirements:
250
- - - ! '>='
259
+ - - ! '>'
251
260
  - !ruby/object:Gem::Version
252
- version: '0'
261
+ version: 1.3.1
253
262
  requirements: []
254
263
  rubyforge_project: maid
255
264
  rubygems_version: 1.8.11