maid 0.1.2 → 0.1.3.beta.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,4 +1,6 @@
1
1
  *.gem
2
2
  .bundle
3
3
  .roboconf.sh
4
+ .vagrant
5
+ Gemfile.lock
4
6
  doc/*
data/.rspec CHANGED
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --profile
3
+ -fs
@@ -1,3 +1,4 @@
1
1
  rvm:
2
2
  - 1.8.7
3
3
  - 1.9.2
4
+ - 1.9.3
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
data/README.md CHANGED
@@ -1,137 +1,174 @@
1
1
  # Maid
2
2
 
3
- [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=benjaminoakes&url=https://github.com/benjaminoakes/maid&title=maid&language=en_GB&tags=github&category=software)
4
-
5
3
  Be lazy! Let Maid clean up after you, based on rules you define.
6
4
 
5
+ [Installation](https://github.com/benjaminoakes/maid#installation) | [Tutorial](https://github.com/benjaminoakes/maid#tutorial) | [Documentation](http://rubydoc.info/gems/maid/Maid/Tools)
6
+
7
7
  Maid keeps files from sitting around too long, untouched. Many of the downloads and other files you collect can easily be categorized and handled appropriately by rules you define. Let the maid in your computer take care of the easy stuff, so you can spend more of your time on what matters.
8
8
 
9
9
  Think of it like the email filters you might already have, but for files. Worried about things happening that you don't expect? Maid doesn't overwrite files and actions are logged so you can tell what happened.
10
10
 
11
11
  Maid is inspired by the Mac OS X shareware program [Hazel](http://www.noodlesoft.com/hazel.php). This tool was created on Mac OS X 10.6, but should be generally portable to other systems. (Some of the more advanced features such as `downloaded_from` require OS X, however.)
12
12
 
13
- Your rules are defined in Ruby, so easy rules are easy and difficult rules are possible.
13
+ Your rules are defined in Ruby, so easy rules are easy and difficult rules are possible. This also makes Maid a great general-purpose **advanced file renaming tool**.
14
+
15
+ ## Want to help?
16
+
17
+ ### For Users
18
+
19
+ [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=benjaminoakes&url=https://github.com/benjaminoakes/maid&title=maid&language=en_GB&tags=github&category=software)
20
+
21
+ * Participate in [beta testing](https://github.com/benjaminoakes/maid/issues/10)
22
+ * [Report an issue](https://github.com/benjaminoakes/maid/issues) (bug or feature request)
23
+ * Read through the [wiki](https://github.com/benjaminoakes/maid/wiki)
24
+ * Even just [share a link to Maid](https://twitter.com/intent/tweet?related=benjaminoakes&text=Be+lazy%21+Let+Maid+clean+up+after+you%2C+based+on+rules+you+define&url=https%3A%2F%2Fgithub.com%2Fbenjaminoakes%2Fmaid) :)
14
25
 
15
- ![Still Maintained?](http://stillmaintained.com/benjaminoakes/maid.png)
16
- [![Build Status](http://travis-ci.org/benjaminoakes/maid.png)](http://travis-ci.org/benjaminoakes/maid)
26
+ ### For Developers
27
+
28
+ [![Build Status](https://secure.travis-ci.org/benjaminoakes/maid.png)](http://travis-ci.org/benjaminoakes/maid)
29
+ [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/benjaminoakes/maid)
30
+
31
+ * Complete an issue (easy ones [are labelled](https://github.com/benjaminoakes/maid/issues?labels=difficulty-1&page=1&state=open), and issues for future releases are [grouped by milestone](https://github.com/benjaminoakes/maid/issues/milestones)).
32
+ * **Working on an issue?** Please leave a comment so others know.
33
+ * See the [Contributing guide](https://github.com/benjaminoakes/maid/wiki/Contributing)
17
34
 
18
35
  ## Buzz
19
36
 
20
- * [OneThingWell: Maid](http://onethingwell.org/post/30455088809/maid) - August 29th, 2012
21
- * [Maid – Paresseux mais ordonné!](http://korben.info/maid-ruby-script.html) (FR) - August 30th, 2012
37
+ [![OneThingWell Logo](https://raw.github.com/benjaminoakes/maid/master/resources/OneThingWell.png)](http://onethingwell.org/)
22
38
 
23
- <blockquote class="twitter-tweet"><p>gem install maid するとメイドさんが手に入るので Ruby 便利.<a href="https://t.co/gH6XgWJH" title="https://github.com/benjaminoakes/maid">github.com/benjaminoakes/…</a></p>&mdash; りんだん(実際犬) (@Linda_pp) <a href="https://twitter.com/Linda_pp/status/241588990166310912" data-datetime="2012-08-31T17:31:18+00:00">August 31, 2012</a></blockquote>
24
- <script src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
39
+ [Maid](http://onethingwell.org/post/30455088809/maid) - August 29th, 2012
25
40
 
26
- <blockquote class="twitter-tweet"><p><a href="https://t.co/YnOzpwRV" title="https://github.com/benjaminoakes/maid">github.com/benjaminoakes/…</a> 這個拿來整理檔案似乎不錯.... <a href="http://t.co/rUt2f258" title="http://fb.me/1CxgLtmyq">fb.me/1CxgLtmyq</a></p>&mdash; xdite (@xdite) <a href="https://twitter.com/xdite/status/242335478626521088" data-datetime="2012-09-02T18:57:35+00:00">September 2, 2012</a></blockquote>
27
- <script src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
41
+ [![Ruby5 Logo](https://raw.github.com/benjaminoakes/maid/master/resources/ruby5.gif)](http://ruby5.envylabs.com/)
28
42
 
29
- ## Is it any good?
43
+ [Podcast #302](http://ruby5.envylabs.com/episodes/306-episode-302-august-31st-2012) (at 2:45) - August 31st, 2012
30
44
 
31
- Yes.
45
+ [More...](https://github.com/benjaminoakes/maid/wiki/In-the-Media)
32
46
 
33
47
  ## Installation
34
48
 
35
- Maid supports OS X and Ubuntu. Other Unix-like operating systems may work, but are not officially supported. (Contributions are welcome, however.)
49
+ [![Download for Ubuntu](https://github.com/benjaminoakes/maid/raw/master/resources/download-for-ubuntu.png)](https://github.com/benjaminoakes/maid/issues/3)
36
50
 
37
- ### OS X
51
+ #### Offically supported:
38
52
 
39
- Open a terminal and run:
53
+ * **OS:** Mac OS X, Ubuntu
54
+ * **Ruby:** 1.8.7, 1.9.3 (preferred)
40
55
 
41
- gem install maid
56
+ (Other Ruby versions and OSes may work, but are not officially supported. Contributions are welcome, however.)
42
57
 
43
- If you want to install the executable for all users, you may need to give root access:
58
+ ### Manual Installation
44
59
 
45
- sudo gem install maid
60
+ First, you need Ruby:
46
61
 
47
- ### Ubuntu
62
+ * **Mac OS X:** Ruby 1.8.7 comes preinstalled.
63
+ * **Ubuntu:** Ruby is not preinstalled. To install Ruby 1.9.3: `sudo apt-get install ruby1.9.1 # (sic)` ([Interested in a package?](https://github.com/benjaminoakes/maid/issues/3))
48
64
 
49
- #### Ubuntu Software Center
65
+ Then, you can install via RubyGems. Open a terminal and run:
50
66
 
51
- [![Download for Ubuntu](https://github.com/benjaminoakes/maid/raw/master/resources/download-for-ubuntu.png)](https://github.com/benjaminoakes/maid/issues/3)
67
+ sudo gem install maid
52
68
 
53
- #### Manually
69
+ At a later date, you can update by running:
54
70
 
55
- You'll need Ruby and RubyGems installed. Open a terminal and run:
71
+ sudo gem update maid
56
72
 
57
- sudo apt-get install ruby rubygems
73
+ If you decide you don't want Maid installed anymore, remove it:
58
74
 
59
- You might also need to add the RubyGems `bin` directory to your `$PATH`. For example, you might need to add something like this to your `~/.bashrc`:
75
+ sudo gem uninstall maid
60
76
 
61
- export PATH="/var/lib/gems/1.8/bin:$PATH"
62
-
63
- Then install Maid itself:
64
-
65
- gem install maid
77
+ **NOTE:** This does not remove any files under `~/.maid` or crontab entries. Please remove them at your convenience.
66
78
 
67
- If you want to install the executable for all users, you may need to give root access:
79
+ ### Troubleshooting
68
80
 
69
- sudo gem install maid
81
+ * Having multiple Ruby versions installed can confuse things. If you're a Ruby developer, you may prefer to just `gem install maid` with your preferred setup. Ruby 1.9.3 is recommended.
82
+ * Older packages of Ruby for Ubuntu may not automatically add the RubyGems `bin` directory to your `$PATH`. Double check your settings.
70
83
 
71
84
  ## Tutorial
72
85
 
73
- Maid rules are defined using Ruby, with some common operations made easier with a small DSL (Domain Specific Language). Here's a sample:
86
+ In a nutshell, Maid uses "rules" to define how files are handled. Once you have rules defined, you can either test what cleaning would do (`maid clean -n`) or actually clean (`maid clean`).
74
87
 
75
- Maid.rules do
76
- rule 'Old files downloaded while developing/testing' do
77
- dir('~/Downloads/*').each do |path|
78
- if downloaded_from(path).any? {|u| u.match 'http://localhost'} && 1.week.since?(last_accessed(path))
79
- trash(path)
80
- end
81
- end
88
+ To generate a [sample rules file](https://github.com/benjaminoakes/maid/blob/master/lib/maid/rules.sample.rb), run:
89
+
90
+ ```bash
91
+ maid sample
92
+ ```
93
+
94
+ Maid rules are defined using Ruby, with some common operations made easier with a small DSL (Domain Specific Language).
95
+
96
+ For example, this is a rule:
97
+
98
+ ```ruby
99
+ Maid.rules do
100
+ rule 'Old files downloaded while developing/testing' do
101
+ dir('~/Downloads/*').each do |path|
102
+ if downloaded_from(path).any? {|u| u.match 'http://localhost'} && 1.week.since?(last_accessed(path))
103
+ trash(path)
82
104
  end
83
105
  end
106
+ end
107
+ end
108
+ ```
109
+
110
+ If you're new to Ruby and would prefer a more traditional `for` loop, you can also do this:
111
+
112
+ ```ruby
113
+ Maid.rules do
114
+ rule 'My rule' do
115
+ for path in dir('~/Downloads/*')
116
+ # ...
117
+ end
118
+ end
119
+ end
120
+ ```
84
121
 
85
122
  Before you start running your rules, you'll likely want to be able to test them. Here's how:
86
123
 
87
- # No actions are taken; you just see what would happen with your rules as defined.
88
- maid --dry-run
89
- maid --noop
90
- maid -n
124
+ ```bash
125
+ # No actions are taken; you just see what would happen with your rules as defined.
126
+ maid clean --dry-run # Synonyms: -n, --noop
127
+ ```
91
128
 
92
129
  To run your rules on demand, you can run `maid` manually:
93
130
 
94
- maid # Run the rules at ~/.maid/rules.rb, logging to ~/.maid/maid.log
95
- maid -r some_rules.rb # Run the rules in the file 'some_rules.rb', logging to ~/.maid/maid.log
131
+ ```bash
132
+ maid clean # Run the rules at ~/.maid/rules.rb, logging to ~/.maid/maid.log
133
+ maid clean -r some_rules.rb # Run the rules in the file 'some_rules.rb', logging to ~/.maid/maid.log
134
+ ```
96
135
 
97
136
  So, for example, if this is `some_rules.rb`:
98
137
 
99
- Maid.rules do
100
- rule 'downloaded PDF books' do
101
- dir('~/Downloads/*.pdf').each do |path|
102
- move(path, '~/Books')
103
- end
104
- end
105
- end
138
+ ```ruby
139
+ Maid.rules do
140
+ rule 'downloaded PDF books' do
141
+ move(dir('~/Downloads/*.pdf'), '~/Books')
142
+ end
143
+ end
144
+ ```
106
145
 
107
- This is the command to test, as well as some sample output:
146
+ Then, this is the command to test, as well as some sample output:
108
147
 
109
- $ maid -nr some_rules.rb
148
+ $ maid clean -nr some_rules.rb
110
149
  Rule: downloaded PDF books
111
150
  mv "/Users/ben/Downloads/book.pdf" "/Users/ben/Books/"
112
151
  mv "/Users/ben/Downloads/issue12.pdf" "/Users/ben/Books/"
113
152
  mv "/Users/ben/Downloads/spring2011newsletter.pdf" "/Users/ben/Books/"
114
153
 
115
- For more DSL helper methods, please see the documentation of [Maid::Tools](http://rubydoc.info/gems/maid/0.1.0/Maid/Tools).
154
+ For help with command line usage, run `maid help`. For more DSL helper methods, please see the documentation of [Maid::Tools](http://rubydoc.info/gems/maid/Maid/Tools).
116
155
 
117
156
  ### Automation
118
157
 
119
158
  Once you get a hang for what you can do with Maid, let it do its stuff automatically throughout the day. You'll find your computer stays a little tidier with as you teach it how to handle your common files.
120
159
 
121
- To do this, edit your crontab in your tool of choice and have it invoke the `maid` command. The `--silent` option is provided to keep this from emailing you, if desired. A log of the actions taken is kept at `~/.maid/maid.log`.
160
+ To do this, edit your crontab in your tool of choice:
122
161
 
123
- Example for every day at 1am:
162
+ crontab -e
124
163
 
125
- # minute hour day_of_month month day_of_week command_to_execute
126
- 0 1 * * * /bin/bash -li -c "maid --silent"
164
+ ...and have it invoke the `maid clean` command. The `--silent` option is provided to keep this from emailing you, if desired. A log of the actions taken is kept at `~/.maid/maid.log`.
127
165
 
128
- Both Mac OS X and Linux support callbacks when folders are changed, and that may be a forthcoming feature in Maid. That said, I find `cron` to take care of most of my needs.
129
-
130
- ## Sample
166
+ Example for every day at 1am:
131
167
 
132
- For a sample rules file, run:
168
+ # minute hour day_of_month month day_of_week command_to_execute
169
+ 0 1 * * * /bin/bash -li -c "maid clean --silent"
133
170
 
134
- maid sample
171
+ Both Mac OS X and Ubuntu support callbacks when folders are changed, and that may be a forthcoming feature in Maid. That said, I find `cron` to take care of most of my needs.
135
172
 
136
173
  ## Warranty
137
174
 
data/Rakefile CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'rake'
2
- require 'rake/rdoctask'
3
2
  require 'rspec/core/rake_task'
4
3
  require 'bundler'
5
4
 
@@ -7,10 +6,8 @@ task :default => :spec
7
6
 
8
7
  Bundler::GemHelper.install_tasks
9
8
 
10
- Rake::RDocTask.new do |rd|
11
- rd.rdoc_dir = 'doc'
12
- rd.main = 'README.rdoc'
13
- rd.rdoc_files.include('README.rdoc', 'lib/**/*.rb')
14
- end
15
-
16
9
  RSpec::Core::RakeTask.new(:spec)
10
+
11
+ task :console do
12
+ sh 'irb -I lib -r maid'
13
+ end
@@ -0,0 +1,11 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+
4
+ Vagrant::Config.run do |config|
5
+ # The base precise64 box can be found at http://files.vagrantup.com/precise64.box
6
+ #
7
+ # For more info, please see https://github.com/benjaminoakes/maid/wiki/Contributing
8
+ config.vm.box = 'precise64'
9
+
10
+ config.vm.provision(:shell, :path => 'script/provision')
11
+ end
@@ -1,9 +1,14 @@
1
+ require 'deprecated'
2
+ Deprecated.set_action(:warn)
3
+
1
4
  module Maid
2
5
  autoload :App, 'maid/app'
3
6
  autoload :Maid, 'maid/maid'
4
7
  autoload :Tools, 'maid/tools'
5
8
  autoload :NumericExtensions, 'maid/numeric_extensions'
9
+ autoload :Platform, 'maid/platform'
6
10
  autoload :Rule, 'maid/rule'
11
+ autoload :TrashMigration, 'maid/trash_migration'
7
12
  autoload :VERSION, 'maid/version'
8
13
 
9
14
  class << self
@@ -23,7 +28,8 @@ module Maid
23
28
  end
24
29
 
25
30
  class Numeric
26
- include Maid::NumericExtensions
31
+ include Maid::NumericExtensions::Time
32
+ include Maid::NumericExtensions::SizeToKb
27
33
  end
28
34
 
29
35
  # TODO Is there a no-conflict way of including the extensions?
@@ -17,9 +17,17 @@ class Maid::App < Thor
17
17
  method_option :silent, :type => :boolean, :aliases => %w[-s]
18
18
  def clean
19
19
  maid = Maid::Maid.new(maid_options(options))
20
+
21
+ if Maid::TrashMigration.needed?
22
+ migrate_trash
23
+ return
24
+ end
25
+
20
26
  unless options.silent? || options.noop?
21
27
  say "Logging actions to #{maid.log_device.inspect}"
22
28
  end
29
+
30
+ maid.load_rules
23
31
  maid.clean
24
32
  end
25
33
 
@@ -47,6 +55,7 @@ class Maid::App < Thor
47
55
  h[:file_options] = {:noop => true}
48
56
 
49
57
  unless options['silent']
58
+ h[:logger] = false
50
59
  h[:log_device] = STDOUT
51
60
  h[:log_formatter] = lambda { |_, _, _, msg| "#{msg}\n" }
52
61
  end
@@ -59,4 +68,48 @@ class Maid::App < Thor
59
68
  h
60
69
  end
61
70
  end
71
+
72
+ private
73
+
74
+ # Migrate trash to correct directory on Linux due to a configuration bug in previous releases.
75
+ def migrate_trash
76
+ migration = Maid::TrashMigration
77
+ banner('Trash Migration', :yellow)
78
+
79
+ say <<-EOF
80
+
81
+ You are using Linux and have a "~/.Trash" directory. If you used Maid 0.1.2 or earlier, that directory may exist because Maid incorrectly moved trash files there.
82
+
83
+ But no worries. Maid can migrate those files to the correct place.
84
+
85
+ EOF
86
+
87
+ response = ask("Would you like Maid to move the files in #{ migration.incorrect_trash.inspect } to #{ migration.correct_trash.inspect }?", :limited_to => %w(Y N))
88
+
89
+ case response
90
+ when 'Y'
91
+ say('')
92
+ say('Migrating trash...')
93
+
94
+ migration.perform
95
+
96
+ say('Migrated. See the Maid log for details.')
97
+ when 'N'
98
+ say <<-EOF
99
+
100
+ Running Maid again will continue to give this warning until #{ migration.incorrect_trash.inspect } no longer exists, or the environment variable MAID_NO_MIGRATE_TRASH has a value.
101
+
102
+ Exiting...
103
+ EOF
104
+
105
+ exit -1
106
+ else
107
+ raise "Reached 'impossible' case (response: #{ response.inspect })"
108
+ end
109
+ end
110
+
111
+ def banner(text, color = nil)
112
+ say(text, color)
113
+ say('-' * text.length, color)
114
+ end
62
115
  end
@@ -1,17 +1,18 @@
1
1
  require 'fileutils'
2
2
  require 'logger'
3
3
 
4
+ require 'xdg'
5
+
4
6
  # Maid cleans up according to the given rules, logging what it does.
5
7
  class Maid::Maid
6
8
  DEFAULTS = {
7
9
  :progname => 'Maid',
8
10
  :log_device => File.expand_path('~/.maid/maid.log'),
9
11
  :rules_path => File.expand_path('~/.maid/rules.rb'),
10
- :trash_path => File.expand_path('~/.Trash'),
11
12
  :file_options => {:noop => false}, # for FileUtils
12
13
  }.freeze
13
14
 
14
- attr_reader :file_options, :log_device, :rules, :rules_path, :trash_path
15
+ attr_reader :file_options, :logger, :log_device, :rules, :rules_path, :trash_path
15
16
  include ::Maid::Tools
16
17
 
17
18
  # Make a new Maid, setting up paths for the log and trash.
@@ -23,18 +24,24 @@ class Maid::Maid
23
24
  def initialize(options = {})
24
25
  options = DEFAULTS.merge(options.reject { |k, v| v.nil? })
25
26
 
26
- @log_device = options[:log_device]
27
- FileUtils.mkdir_p(File.dirname(@log_device)) unless @log_device.kind_of?(IO)
27
+ # TODO: Refactor and simplify (see also https://github.com/benjaminoakes/maid/pull/48#discussion_r1683942)
28
+ @logger = unless options[:logger]
29
+ @log_device = options[:log_device]
30
+ FileUtils.mkdir_p(File.dirname(@log_device)) unless @log_device.kind_of?(IO)
31
+ Logger.new(@log_device)
32
+ else
33
+ options[:logger]
34
+ end
28
35
 
29
- @logger = Logger.new(@log_device)
30
36
  @logger.progname = options[:progname]
31
37
  @logger.formatter = options[:log_formatter] if options[:log_formatter]
32
38
 
33
39
  @rules_path = options[:rules_path]
34
- @trash_path = options[:trash_path]
40
+ @trash_path = options[:trash_path] || default_trash_path
35
41
  @file_options = options[:file_options]
36
42
 
37
- # Just in case it isn't there...
43
+ # Just in case they aren't there...
44
+ FileUtils.mkdir_p(File.expand_path('~/.maid'))
38
45
  FileUtils.mkdir_p(@trash_path)
39
46
 
40
47
  @rules = []
@@ -47,7 +54,6 @@ class Maid::Maid
47
54
  @logger.info 'Started'
48
55
  end
49
56
 
50
- add_rules(@rules_path)
51
57
  follow_rules
52
58
 
53
59
  unless @log_device.kind_of?(IO)
@@ -55,8 +61,10 @@ class Maid::Maid
55
61
  end
56
62
  end
57
63
 
58
- # Add the rules at path.
59
- def add_rules(path)
64
+ # Add the rules at rules_path.
65
+ def load_rules
66
+ path = @rules_path
67
+
60
68
  Maid.with_instance(self) do
61
69
  # Using 'Kernel' here to help with testability
62
70
  # Kernel.load must be used for non-".rb" files to be required, it seems.
@@ -100,4 +108,18 @@ private
100
108
  supported = @@supported_commands[command_name]
101
109
  @@supported_commands[command_name] = supported ? supported : !%x(which #{command_name}).empty?
102
110
  end
111
+
112
+ def default_trash_path
113
+ # TODO: Refactor module declaration so this can be `Platform`
114
+ if Maid::Platform.linux?
115
+ # See the [FreeDesktop.org Trash specification](http://www.ramendik.ru/docs/trashspec.html)
116
+ path = "#{ XDG['DATA_HOME'] }/Trash/files"
117
+ elsif Maid::Platform.osx?
118
+ path = File.expand_path('~/.Trash')
119
+ else
120
+ raise NotImplementedError, "Unknown default trash path (unsupported host OS: #{ Maid::Platform.host_os.inspect })"
121
+ end
122
+
123
+ "#{ path }/"
124
+ end
103
125
  end