dle 0.1.7 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 925684c19f7b8b0f4e34406a8d6954e7a6b3c95b
4
- data.tar.gz: 9fc9e15525c47d1d64d9e60a72778fc4583bc61e
3
+ metadata.gz: c1222ce5b458c3140edf473d1505c02fc789edaf
4
+ data.tar.gz: e172707845f3c78cc6d5bcff8a2f4ae84eae6786
5
5
  SHA512:
6
- metadata.gz: 896a00ec5bb4c4c89b49819d0a276df2cbaa19b6faf2230f2a81b537b77d038b5b8633348d891a99f0bcb6317b34714175daa49bdc7fdc097b3e71f4a0123e65
7
- data.tar.gz: 774d08af7e89e476569a4c69d7184bbc5a949ca5a18368d0e6b3d304de99fe7b4455d3796f66cf090114ff2a76722a4aca44047d8b5dc7feb63fa78e92b87430
6
+ metadata.gz: 730402aa582c113b6904b3fd511c396679b4621a8981e1caafc7faa174adcca70be21e92e8993fd632595ec5db49cf8ee19729491cb316df5579b50519003447
7
+ data.tar.gz: 816a8bb37cde6ecae9b49c40392ea89168222495271794d8a7eb3350236231de006232507f116a9aa055a8cafdb7e774c33ff3eb2fe6367b9d0d1d89ec1d2414
data/README.md CHANGED
@@ -5,11 +5,12 @@ You can copy, move, rename, chmod, chown or remove individual files or directori
5
5
 
6
6
  **BETA product, use at your own risk, use `--simulate` to be sure, always have a backup!**
7
7
 
8
- **[» See it in action!](https://www.youtube.com/watch?v=-xfnx3VQvNQ)**
8
+ [![YouTube](http://img.youtube.com/vi/-xfnx3VQvNQ/mqdefault.jpg)](https://www.youtube.com/watch?v=-xfnx3VQvNQ)
9
+ **[▶ See it in action](https://www.youtube.com/watch?v=-xfnx3VQvNQ)**
9
10
 
10
11
  ## Requirements
11
12
 
12
- You will need a UNIX system with a working Ruby installation, sorry Windozer!
13
+ You will need a UNIX system with a working Ruby (>= 1.9.3) installation, sorry Windozer!
13
14
 
14
15
  ## Installation
15
16
 
@@ -28,16 +29,26 @@ Note that you need a blocking call to the editor (for GUI editors). Sublime and
28
29
  To get a list of available options invoke DLE with the `--help` or `-h` option:
29
30
 
30
31
  Usage: dle [options] base_directory
32
+ # Application options
31
33
  -d, --dotfiles Include dotfiles (unix invisible)
32
34
  -r, --skip-review Skip review changes before applying
33
35
  -s, --simulate Don't apply changes, show commands instead
34
36
  -f, --file DLFILE Use input file (be careful)
35
37
  -o, --only pattern files, dirs or regexp (without delimiters)
36
38
  e.g.: dle ~/Movies -o "(mov|mkv|avi)$"
39
+ -a, --apply NAMED,FILTERS Filter collection with saved filters
40
+ -q, --query Filter collection with ruby code
41
+ -e, --edit FILTER Edit/create filter scripts
42
+
43
+ # General options
37
44
  -m, --monochrome Don't colorize output
38
45
  -h, --help Shows this help
39
46
  -v, --version Shows version and other info
40
47
  -z Do not check for updates on GitHub (with -v/--version)
48
+ --console Start console to play around with the collection (requires pry)
49
+
50
+
51
+
41
52
 
42
53
  Change into a directory you want to work with and invoke DLE:
43
54
 
@@ -62,6 +73,23 @@ Your editor will open with a list of your directory structure which you can edit
62
73
  * Copy
63
74
  * Delete
64
75
 
76
+
77
+ ### Filters
78
+
79
+ You can easily filter your movies with Ruby. It's not hard, just look at these examples.
80
+
81
+ ```ruby
82
+ # Filter by name, for regex see http://rubular.com
83
+ @fs.index.reject! {|inode, node| node.basename =~ /whatever/i }
84
+
85
+ # Only big files
86
+ @fs.index.select! {|inode, node| node.file? && node.size > 1024 * 1024 * 10 }
87
+
88
+ # Sort by size
89
+ @fs.index.replace Hash[@fs.index.sort_by{|inode, node| node.size }.reverse]
90
+ ```
91
+
92
+
65
93
  ## Caveats
66
94
 
67
95
  DLE relies on inode values, do not use with hardlinks! This may lead to unexpected file operations or data loss!
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.7
1
+ 1.0.1
data/lib/dle.rb CHANGED
@@ -18,6 +18,7 @@ require "dle/filesystem/destructive"
18
18
  require "dle/filesystem/softnode"
19
19
  require "dle/filesystem/node"
20
20
  require "dle/filesystem"
21
+ require "dle/application/filter"
21
22
  require "dle/application/dispatch"
22
23
  require "dle/application"
23
24
 
@@ -8,6 +8,7 @@ module Dle
8
8
  class Application
9
9
  attr_reader :opts
10
10
  include Dispatch
11
+ include Filter
11
12
  include Helpers
12
13
 
13
14
  # =========
@@ -30,27 +31,47 @@ module Dle
30
31
  @editor = which_editor
31
32
  @opts = {
32
33
  dispatch: :index,
34
+ console: false,
33
35
  dotfiles: false,
34
36
  check_for_updates: true,
35
37
  review: true,
38
+ select_scripts: false,
36
39
  simulate: false,
40
+ query: false,
37
41
  }
38
42
  yield(self)
39
43
  end
40
44
 
45
+ def collection_size_changed cold, cnew, reason = nil
46
+ if cold != cnew
47
+ log(
48
+ "We have filtered " << c("#{cnew}", :magenta) <<
49
+ c(" nodes") << c(" (#{cnew - cold})", :red) <<
50
+ c(" from originally ") << c("#{cold}", :magenta) <<
51
+ (reason ? c(" (#{reason})", :blue) : "")
52
+ )
53
+ end
54
+ end
55
+
41
56
  def parse_params
42
57
  @optparse = OptionParser.new do |opts|
43
58
  opts.banner = "Usage: dle [options] base_directory"
44
59
 
60
+ opts.separator(c "# Application options", :blue)
45
61
  opts.on("-d", "--dotfiles", "Include dotfiles (unix invisible)") { @opts[:dotfiles] = true }
46
62
  opts.on("-r", "--skip-review", "Skip review changes before applying") { @opts[:review] = false }
47
63
  opts.on("-s", "--simulate", "Don't apply changes, show commands instead") { @opts[:simulate] = true ; @opts[:review] = false }
48
64
  opts.on("-f", "--file DLFILE", "Use input file (be careful)") {|f| @opts[:input_file] = f }
49
65
  opts.on("-o", "--only pattern", c("files", :blue) << c(", ") << c("dirs", :blue) << c(" or regexp (without delimiters)"), " e.g.:" << c(%{ dle ~/Movies -o "(mov|mkv|avi)$"}, :blue)) {|p| @opts[:pattern] = p }
66
+ opts.on("-a", "--apply NAMED,FILTERS", Array, "Filter collection with saved filters") {|s| @opts[:select_scripts] = s }
67
+ opts.on("-q", "--query", "Filter collection with ruby code") { @opts[:query] = true }
68
+ opts.on("-e", "--edit FILTER", "Edit/create filter scripts") {|s| @opts[:dispatch] = :edit_script; @opts[:select_script] = s }
69
+ opts.separator("\n" << c("# General options", :blue))
50
70
  opts.on("-m", "--monochrome", "Don't colorize output") { logger.colorize = false }
51
71
  opts.on("-h", "--help", "Shows this help") { @opts[:dispatch] = :help }
52
72
  opts.on("-v", "--version", "Shows version and other info") { @opts[:dispatch] = :info }
53
73
  opts.on("-z", "Do not check for updates on GitHub (with -v/--version)") { @opts[:check_for_updates] = false }
74
+ opts.on("--console", "Start console to play around with the collection (requires pry)") {|f| @opts[:console] = true }
54
75
  end
55
76
 
56
77
  begin
@@ -14,6 +14,12 @@ module Dle
14
14
  end
15
15
  end
16
16
 
17
+ def dispatch_edit_script
18
+ log("Opening file in editor...")
19
+ f = record_filter(filter_script(@opts[:select_script]))
20
+ log("Saved file " << c(f, :magenta))
21
+ end
22
+
17
23
  def dispatch_help
18
24
  logger.log_without_timestr do
19
25
  @optparse.to_s.split("\n").each(&method(:log))
@@ -96,93 +102,123 @@ module Dle
96
102
  abort("Base directory is empty or not readable", 1) if @fs.index.empty?
97
103
  log("indexed #{c "#{human_number @fs.index.count} nodes", :magenta}") if @fs.index.count > 1000
98
104
 
99
- file = "#{Dir.tmpdir}/#{SecureRandom.urlsafe_base64}"
100
- begin
101
- # read input file or open editor
102
- if @opts[:input_file]
103
- ifile = File.expand_path(@opts[:input_file])
104
- if FileTest.file?(ifile) && FileTest.readable?(ifile)
105
- log "processing file..."
106
- @dlfile = DlFile.parse(ifile)
105
+ if @opts[:console]
106
+ log "You have access to the collection with " << c("@fs", :magenta)
107
+ log "Apply existent select script with " << c("apply_filter(@fs, 'filter_name')", :magenta)
108
+ log "Type " << c("exit", :magenta) << c(" to leave the console.")
109
+ begin
110
+ binding.pry(quiet: true)
111
+ abort c("No changes, nothing to do..."), 0
112
+ rescue NoMethodError => ex
113
+ raise ex unless ex.message["undefined method `pry'"]
114
+ abort c("The pry gem is required to display the console. Please install it: " << c("gem install pry", :blue)), 3
115
+ end
116
+ else
117
+ file = "#{Dir.tmpdir}/#{SecureRandom.urlsafe_base64}"
118
+ begin
119
+ # read input file or open editor
120
+ if @opts[:input_file]
121
+ ifile = File.expand_path(@opts[:input_file])
122
+ if FileTest.file?(ifile) && FileTest.readable?(ifile)
123
+ log "processing file..."
124
+ @dlfile = DlFile.parse(ifile)
125
+ else
126
+ abort "Input file not readable: " << c(ifile, :magenta)
127
+ end
107
128
  else
108
- abort "Input file not readable: " << c(ifile, :magenta)
109
- end
110
- else
111
- FileUtils.mkdir_p(File.dirname(file)) if !FileTest.exist?(File.dirname(file))
112
- if !FileTest.exist?(file) || File.read(file).strip.empty?
113
- notifier do
114
- sleep 3
115
- log "writing result list to file..."
116
- end.perform do
117
- File.open(file, "w") {|f| f.write @fs.to_dlfile }
129
+ old_count = @fs.index.count
130
+ if @opts[:query]
131
+ apply_filter(@fs, record_filter)
132
+ collection_size_changed old_count, @fs.index.count, "custom filter"
133
+ old_count = @fs.index.count
118
134
  end
135
+
136
+ # filter
137
+ (@opts[:select_scripts] || []).each do |filter|
138
+ apply_filter(@fs, filter_script(filter))
139
+ collection_size_changed old_count, @fs.index.count, "filter: #{filter}"
140
+ old_count = @fs.index.count
141
+ end
142
+
143
+ # save file
144
+ FileUtils.mkdir_p(File.dirname(file)) if !FileTest.exist?(File.dirname(file))
145
+ if !FileTest.exist?(file) || File.read(file).strip.empty?
146
+ notifier do
147
+ sleep 3
148
+ log "writing result list to file..."
149
+ end.perform do
150
+ File.open(file, "w") {|f| f.write @fs.to_dlfile }
151
+ end
152
+ end
153
+
154
+ # open editor
155
+ log "open list for editing..."
156
+ open_editor(file)
157
+ log "processing file..."
158
+ @dlfile = DlFile.parse(file)
119
159
  end
120
- log "open list for editing..."
121
- open_editor(file)
122
- log "processing file..."
123
- @dlfile = DlFile.parse(file)
124
- end
125
160
 
126
- # delta changes
127
- @delta = @fs.delta(@dlfile)
161
+ # delta changes
162
+ @delta = @fs.delta(@dlfile)
128
163
 
129
- # no changes
130
- if @delta.all?{|_, v| v.empty? }
131
- abort c("No changes, nothing to do..."), 0
132
- end
164
+ # no changes
165
+ if @delta.all?{|_, v| v.empty? }
166
+ abort c("No changes, nothing to do..."), 0
167
+ end
133
168
 
134
- # review
135
- if @opts[:review]
136
- @delta.each do |action, snodes|
137
- logger.ensure_prefix c("[#{action}]\t", :magenta) do
138
- snodes.each do |snode|
139
- if [:chown, :chmod].include?(action)
140
- log(c("#{snode.node.relative_path} ", :blue) << c(snode.is, :red) << c(" » ") << c(snode.should, :green))
141
- elsif [:cp, :mv].include?(action)
142
- log(c(snode.is, :red) << c(" » ") << c(snode.should, :green))
143
- else
144
- log(c(snode.is, :red) << " (#{snode.snode.mode})")
169
+ # review
170
+ if @opts[:review]
171
+ @delta.each do |action, snodes|
172
+ logger.ensure_prefix c("[#{action}]\t", :magenta) do
173
+ snodes.each do |snode|
174
+ if [:chown, :chmod].include?(action)
175
+ log(c("#{snode.node.relative_path} ", :blue) << c(snode.is, :red) << c(" » ") << c(snode.should, :green))
176
+ elsif [:cp, :mv].include?(action)
177
+ log(c(snode.is, :red) << c(" » ") << c(snode.should, :green))
178
+ else
179
+ log(c(snode.is, :red) << " (#{snode.snode.mode})")
180
+ end
145
181
  end
146
182
  end
147
183
  end
148
- end
149
184
 
150
- answer = ask("Do you want to apply these changes? [yes/no/edit]")
151
- while !["y", "yes", "n", "no", "e", "edit"].include?(answer.downcase)
152
- answer = ask("Please be explicit, yes/no/edit:")
185
+ answer = ask("Do you want to apply these changes? [yes/no/edit]")
186
+ while !["y", "yes", "n", "no", "e", "edit"].include?(answer.downcase)
187
+ answer = ask("Please be explicit, yes/no/edit:")
188
+ end
189
+ raise "retry" if ["e", "edit"].include?(answer.downcase)
190
+ abort("Aborted, nothing changed", 0) if !["y", "yes"].include?(answer.downcase)
153
191
  end
154
- raise "retry" if ["e", "edit"].include?(answer.downcase)
155
- abort("Aborted, nothing changed", 0) if !["y", "yes"].include?(answer.downcase)
192
+ rescue
193
+ $!.message == "retry" ? retry : raise
156
194
  end
157
- rescue
158
- $!.message == "retry" ? retry : raise
159
- end
160
195
 
161
- # apply changes
162
- log "#{@opts[:simulate] ? "Simulating" : "Applying"} changes..."
163
- @fs.opts[:verbose] = false
164
- total_actions = @delta.map{|_, nodes| nodes.count }.inject(&:+)
165
- actions_performed = 0
166
- begin
167
- notifier do
168
- loop do
169
- if BASH_ENABLED
170
- logger.raw("\033]0;#{@opts[:simulate] ? "Simulated" : "Peformed"} #{human_number actions_performed}/#{human_number total_actions} changes\007", :print)
196
+ # apply changes
197
+ log "#{@opts[:simulate] ? "Simulating" : "Applying"} changes..."
198
+ @fs.opts[:verbose] = false
199
+ total_actions = @delta.map{|_, nodes| nodes.count }.inject(&:+)
200
+ actions_performed = 0
201
+ begin
202
+ notifier do
203
+ loop do
204
+ if BASH_ENABLED
205
+ logger.raw("\033]0;#{@opts[:simulate] ? "Simulated" : "Peformed"} #{human_number actions_performed}/#{human_number total_actions} changes\007", :print)
206
+ end
207
+ sleep 1
171
208
  end
172
- sleep 1
173
- end
174
- end.perform do
175
- @delta.each do |action, snodes|
176
- logger.ensure_prefix c("[apply-#{action}]\t", :magenta) do
177
- snodes.each do |snode|
178
- actions_performed += 1
179
- Filesystem::Destructive.new(self, action, @fs, snode).perform
209
+ end.perform do
210
+ @delta.each do |action, snodes|
211
+ logger.ensure_prefix c("[apply-#{action}]\t", :magenta) do
212
+ snodes.each do |snode|
213
+ actions_performed += 1
214
+ Filesystem::Destructive.new(self, action, @fs, snode).perform
215
+ end
180
216
  end
181
217
  end
182
218
  end
219
+ ensure
220
+ log "#{@opts[:simulate] ? "Simulated" : "Peformed"} #{human_number actions_performed} changes..."
183
221
  end
184
- ensure
185
- log "#{@opts[:simulate] ? "Simulated" : "Peformed"} #{human_number actions_performed} changes..."
186
222
  end
187
223
  end
188
224
  end
@@ -0,0 +1,36 @@
1
+ module Dle
2
+ class Application
3
+ module Filter
4
+ def filter_script name
5
+ File.expand_path("~/.dle/#{name}.rb")
6
+ end
7
+
8
+ def apply_filter collection, file
9
+ app = @app
10
+ eval File.read(file), binding, file
11
+ collection
12
+ end
13
+
14
+ def permute_script collection, file = nil
15
+ file ||= "#{Dir.tmpdir}/#{SecureRandom.urlsafe_base64}"
16
+ FileUtils.mkdir(File.dirname(file)) if !File.exist?(File.dirname(file))
17
+ if !File.exist?(file) || File.read(file).strip.empty?
18
+ File.open(file, "w") {|f| f.puts("# Permute your collection, same as with the selector script filters.") }
19
+ end
20
+ system "#{cfg :application, :editor} #{file}"
21
+ eval File.read(file), binding, file
22
+ collection
23
+ end
24
+
25
+ def record_filter file = nil
26
+ file ||= "#{Dir.tmpdir}/#{SecureRandom.urlsafe_base64}.rb"
27
+ FileUtils.mkdir(File.dirname(file)) if !File.exist?(File.dirname(file))
28
+ if !File.exist?(file) || File.read(file).strip.empty?
29
+ FileUtils.cp("#{ROOT}/lib/dle/application/filter.tpl", file)
30
+ end
31
+ open_editor(file)
32
+ file
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,55 @@
1
+ # TIP: Using vim and want to get rid of this example shit?
2
+ # In nav-mode type: 100dd
3
+
4
+ # Hey there,
5
+ # to filter your records you will use Ruby
6
+ # but don't be afraid, it's fairly simple.
7
+ # Just look at the examples and referenced links.
8
+
9
+ # Use ruby methods to narrow down you result set.
10
+ # * http://www.ruby-doc.org/core-2.1.1/File.html
11
+ # * http://www.ruby-doc.org/core-2.1.1/Enumerable.html
12
+
13
+ # ====================================================
14
+ # = Doc (remove, reuse or comment out the examples!) =
15
+ # ====================================================
16
+
17
+ puts "Filtering in #{@fs.base_dir}"
18
+ @fs.index.select! do |inode, node|
19
+ # node has the following methods
20
+ # * dir => source movie directory (e.g. C:/Movies)
21
+ # * relative_path => relative path to @fs.base_dir
22
+ # * mode => file mode
23
+ # * owner => name of the file owner
24
+ # * group => name of the file group
25
+ # * owngrp => owner and group combined by a colon
26
+ # * basename => alias for File#basename
27
+ # * dirname => alias for File#dirname
28
+ # * extname => alias for File#extname
29
+ # * stat => alias for File#stat
30
+ # * size => alias for File#size
31
+ # * directory? => alias for FileTest#directory?
32
+ # * file? => alias for FileTest#file?
33
+ # * symlink? => alias for FileTest#symlink?
34
+
35
+ # The index is NOT NESTED! If you remove a directory node, all sub nodes
36
+ # will still be in the index!
37
+
38
+ # Set break point to interactively call methods from here.
39
+ # See http://pryrepl.org ory type "help" when you are in the REPL.
40
+ # Use exit or exit! to break out of REPL.
41
+ # binding.pry
42
+
43
+ # --------------------------------------------------------------
44
+
45
+ node.directory? && node.basename =~ /^[a-z0-9]+$/
46
+ end
47
+
48
+ # Filter by name, for regex see http://rubular.com
49
+ @fs.index.reject! {|inode, node| node.basename =~ /whatever/i }
50
+
51
+ # Only big files
52
+ @fs.index.select! {|inode, node| node.file? && node.size > 1024 * 1024 * 10 }
53
+
54
+ # Sort by size
55
+ @fs.index.replace Hash[@fs.index.sort_by{|inode, node| node.size }.reverse]
@@ -35,7 +35,7 @@ module Dle
35
35
  [].tap do |r|
36
36
  col_sizes = table.map{|col| col.map(&:to_s).map(&:length).max }
37
37
  headers.map(&:length).each_with_index do |length, header|
38
- col_sizes[header] = [col_sizes[header], length].max
38
+ col_sizes[header] = [col_sizes[header] || 0, length || 0].max
39
39
  end
40
40
 
41
41
  # header
@@ -1,4 +1,4 @@
1
1
  module Dle
2
- VERSION = "0.1.7"
2
+ VERSION = "1.0.1"
3
3
  UPDATE_URL = "https://raw.githubusercontent.com/2called-chaos/dle/master/VERSION"
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sven Pachnit
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-11 00:00:00.000000000 Z
11
+ date: 2015-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -77,6 +77,8 @@ files:
77
77
  - lib/dle.rb
78
78
  - lib/dle/application.rb
79
79
  - lib/dle/application/dispatch.rb
80
+ - lib/dle/application/filter.rb
81
+ - lib/dle/application/filter.tpl
80
82
  - lib/dle/dl_file.rb
81
83
  - lib/dle/filesystem.rb
82
84
  - lib/dle/filesystem/destructive.rb
@@ -104,9 +106,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
106
  version: '0'
105
107
  requirements: []
106
108
  rubyforge_project:
107
- rubygems_version: 2.2.2
109
+ rubygems_version: 2.0.14
108
110
  signing_key:
109
111
  specification_version: 4
110
112
  summary: Directory List Edit – Edit file structures in your favorite editor!
111
113
  test_files: []
112
- has_rdoc: