tagmv 0.0.2 → 0.0.3

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
- SHA1:
3
- metadata.gz: 5d10d02448926a0c0f986ad631e4d2f295eb7962
4
- data.tar.gz: 323a1d33dd451badf7511b4fee7d6081e228e8c9
2
+ SHA256:
3
+ metadata.gz: 7bc6f70a29aae56b307b09be9a3108070ed3330934020412932d62bac97a1202
4
+ data.tar.gz: b082ddb01729079be19620e3be09e80a3f8f1b51fc311c9f7b7f7fd072232666
5
5
  SHA512:
6
- metadata.gz: b62596a0e6821ae819a67215c1a4c74a43e78d95b55f239c6917a42cbe815fa06d0b108b8000ca9e2001508030be28908ebe32544df5494096cf81561afb3284
7
- data.tar.gz: c4821dfdb7491f3951d9729d74055342d9c5bc6b6155543cfa2a8832618f3862a3187c446c2305a14a40ea3b80d3bbe17d432c083a383a8d67d0a9cb39d86d2e
6
+ metadata.gz: 19567f27d8539032061a6bcd615f4289466c19f991f1c417a56916c4ef27dd1a87ced04c28a575c85ee920c6f57dbc57db56ad51cea15d4566ba827eb8235e5a
7
+ data.tar.gz: fd6e0bc16ac871938088ceba64b251b8a088ec3781fb74c4a4b73d33844c3b52c49ae3c02321e918c664b497b238c4f30cb4bfeda7b24b0160891c230907a6fb
data/README.md CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  The ultimate keep-your-files-organized solution!
4
4
 
5
- Moves your files into directories that represent tags, these tags are kept organized as a hierarchy according to tag counts.
5
+ Moves your files into directories that represent tags, these tags are kept organized as a hierarchy according to usage.
6
6
 
7
7
  Tag all your files with multiple tags, and watch them end up organized!
8
8
 
9
- Works using the most basic parts of the filesystem - no FUSE, no symbolic or hard links.
9
+ Relies on convention-only, no FUSE, no symbolic links, no hard links. No special tools required.
10
10
 
11
11
  ## Installation
12
12
 
@@ -18,17 +18,29 @@ Works using the most basic parts of the filesystem - no FUSE, no symbolic or har
18
18
 
19
19
  This will move your files and directories into:
20
20
 
21
- ~/t/tag1./tag2./tag3./
21
+ ~/t/tag1-/tag2-/tag3-/
22
22
 
23
- As you tag more files and folders, it will order the tag directories according to the most popular tags, keeping things organized for you.
23
+ As you tag more files and folders, it will re-order the tag directories by the most commonly used tags, keeping your files automatically organized for you.
24
24
 
25
25
  ## Current features
26
26
 
27
- Default directory is "~/t/" (not configurable yet, oops)
27
+ Default root directory for all your tagged files is `~/t/` (not configurable yet)
28
28
 
29
- Supports top level tags - so that you can "pin" certain tags to be the top level directory
29
+ ## Configuration
30
30
 
31
- Config file: ~/.tagmv.yml currently supports the top level tags (no easy way to update config yet)
31
+ Configuration file: `~/.tagmv.yml`
32
+
33
+ Supports top level tags - so that you can "pin" certain tags to always show as the top level directories within `~/t/`
34
+
35
+ ## Commands
36
+
37
+ `-d, --dry-run` Check to see what gets moved where
38
+
39
+ `-r, --reorder` **[default]** Move everything in `~/t/` into order of tag usage (example: `tagmv -r`)
40
+
41
+ `-s, --skip-reorder` Skip reorder (e.g. you are editing tagged files and don't want them moved around yet)
42
+
43
+ `-t, --tags *tags` Tags for your files or directories, as many as you want
32
44
 
33
45
 
34
46
  ## Upcoming features
data/lib/tagmv.rb CHANGED
@@ -3,5 +3,7 @@ require 'tagmv/version'
3
3
  require 'tagmv/config'
4
4
  require 'tagmv/entry'
5
5
  require 'tagmv/filesystem'
6
+ require 'tagmv/options'
6
7
  require 'tagmv/prune_path'
7
8
  require 'tagmv/tree'
9
+
@@ -5,26 +5,50 @@ module Tagmv
5
5
  extend self
6
6
 
7
7
  Choice.options do
8
- header "\033[1m\033[32mtagmv\033[0m\033[0m: A Directory-based Tagging Organizer"
8
+ header "A Directory-based Tagging Organizer"
9
+ header ""
10
+ header "Usage:"
11
+ header " $ tagmv file1 file2 directory1 directory2 -t tag1 tag2 tag3 -d"
9
12
  header ""
10
13
  header "Options:"
11
14
 
12
15
  footer ""
13
- footer "tagmv by James Robey (https://github.com/foucist/tagmv/)"
16
+ footer "tagmv by #{Tagmv::AUTHORS.join(', ')} (#{Tagmv::HOMEPAGE})"
17
+
18
+ option :dry_run do
19
+ short '-d'
20
+ long '--dry-run'
21
+ desc 'Check to see what gets moved where'
22
+ end
23
+
24
+ option :reorder do
25
+ short '-r'
26
+ long '--reorder'
27
+ desc 'Move all tagged files & directories into order of tag usage [default]'
28
+ end
29
+
30
+ option :skip_reorder do
31
+ short '-s'
32
+ long '--skip-reorder'
33
+ desc "Skip reorder (for example: you are editing tagged files and don't want them moved around yet)"
34
+ end
14
35
 
15
- option :tags, :required => true do
36
+ option :tags do
16
37
  short '-t'
17
38
  long '--tags *tags'
18
- desc 'The hostname or ip of the host to bind to (default 127.0.0.1)'
39
+ desc 'Tags for your files or directories, as many as you want'
19
40
  end
20
41
  end
21
42
 
22
43
  def parse
23
- return Choice.help if Choice.rest.empty?
44
+ return Choice.help if !Choice.choices[:reorder] && (Choice.choices.empty? || Choice.rest.empty?)
24
45
 
25
46
  opts = Hash.new
26
- opts[:files] = Choice.rest
27
- opts[:tags] = Choice.choices[:tags]
47
+ opts[:files] = Choice.rest
48
+ opts[:dry_run] = Choice.choices[:dry_run]
49
+ opts[:tags] = Choice.choices[:tags]
50
+ opts[:reorder] = Choice.choices[:reorder]
51
+ opts[:skip_reorder]= Choice.choices[:skip_reorder]
28
52
  opts
29
53
  end
30
54
  end
@@ -7,25 +7,42 @@ module Tagmv
7
7
  attr_accessor :root
8
8
  end
9
9
 
10
- attr_reader :tags, :files, :tag_order, :top_level_tags
10
+ attr_reader :tags, :files, :reorder, :tag_order, :top_level_tags
11
11
  def initialize(opts={})
12
- @tags = opts[:tags].map {|t| scrub_tag(t) }
13
- @files = opts[:files].map {|f| File.expand_path(f) }.select {|f| File.exist?(f) }
12
+ @tags = scrub_tags(opts[:tags])
13
+ @files = opts[:files]
14
+ @dry_run = opts[:dry_run]
15
+ @reorder = opts[:reorder]
14
16
  @tag_order = opts[:tag_order]
15
17
  @top_level_tags = opts[:top_level_tags]
16
18
  end
17
19
 
18
- def scrub_tag(tag)
19
- # only keep legit file characters & remove trailing periods
20
- tag.gsub(/[^0-9A-Za-z\.\-\_]|[\.]+$/, '')
20
+ def scrub_tags(tags)
21
+ # only keep legit file characters & remove trailing periods, remove duplicates after
22
+ bad_chars = /^[\-]|[^0-9A-Za-z\.\-\_]|[\.]+$/
23
+ tags.map {|t| t.gsub(bad_chars, '') }.uniq
21
24
  end
22
25
 
23
- def tag_order
24
- top_level_tags | @tag_order
26
+ def scrub_files
27
+ files.select do |file|
28
+ path = File.expand_path(file)
29
+ if File.exist?(path)
30
+ path
31
+ else
32
+ puts "tmv: rename #{file} to #{target_dir}/#{File.basename(file)}: #{Errno::ENOENT.exception}"
33
+ false
34
+ end
35
+ end
36
+ end
37
+
38
+ def tags_in_order
39
+ return tags unless reorder
40
+
41
+ (top_level_tags | tag_order) & tags
25
42
  end
26
43
 
27
44
  def tag_dirs
28
- (tag_order & tags).map {|x| x.gsub(/$/, '.') }
45
+ tags_in_order.map {|x| x.gsub(/$/, '-') }
29
46
  end
30
47
 
31
48
  def target_dir
@@ -33,16 +50,31 @@ module Tagmv
33
50
  end
34
51
 
35
52
  def prepare_dir
36
- FileUtils.mkdir_p(target_dir)
53
+ @@prepare_dir ||= Hash.new do |h, key|
54
+ h[key] = FileUtils.mkdir_p(key, options)
55
+ end
56
+ @@prepare_dir[target_dir]
37
57
  end
38
58
 
39
59
  def move_files
40
- FileUtils.mv(files, target_dir)
60
+ # skip duplicate moves
61
+ return if reorder && scrub_files.size == 1 && (scrub_files.first.sub(target_dir + '/','') !=~ /\//)
62
+
63
+ FileUtils.mv(scrub_files, target_dir, options)
41
64
  rescue ArgumentError
42
65
  end
43
66
 
44
67
  def transfer
45
68
  prepare_dir && move_files
46
69
  end
70
+
71
+ private
72
+ def options
73
+ if @dry_run
74
+ {noop: true, verbose: true}
75
+ else
76
+ {}
77
+ end
78
+ end
47
79
  end
48
80
  end
@@ -0,0 +1,24 @@
1
+ module Tagmv
2
+ class Options
3
+ attr_accessor :additions
4
+ def initialize(opts = {})
5
+ @additions = opts
6
+ end
7
+
8
+ def input
9
+ Tagmv::CommandLine.parse || {}
10
+ end
11
+
12
+ def load_config
13
+ Tagmv::Config.new.load
14
+ end
15
+
16
+ def options
17
+ return if @options
18
+
19
+ @options = load_config
20
+ @options.merge(additions)
21
+ @options.merge(input)
22
+ end
23
+ end
24
+ end
@@ -6,7 +6,7 @@ module Tagmv
6
6
  end
7
7
 
8
8
  def tag_dir?
9
- path =~ /\.$/ && path !~ Tagmv::Tree.false_tag_regex
9
+ path =~ /..-$/ && path !~ Tagmv::Tree.false_tag_regex
10
10
  end
11
11
 
12
12
  def empty_dir?
data/lib/tagmv/runner.rb CHANGED
@@ -2,27 +2,32 @@ module Tagmv
2
2
  module Runner
3
3
  extend self
4
4
 
5
- def tree
6
- @tree ||= Tagmv::Tree.scan_tree_entries
7
- end
8
-
9
- def update_tree
10
- opts = Tagmv::CommandLine.parse
11
- tree.with(opts)
12
- end
13
-
14
- def move_files
5
+ def reorder_files
15
6
  tree.entries.each do |entry|
16
- tfs = Tagmv::Filesystem.new(tags: entry.tags, files: entry.files, tag_order: tree.tag_order, top_level_tags: @opts[:top_level_tags])
17
- tfs.transfer
7
+ fs_options = options.merge(tags: entry.tags, files: entry.files, tag_order: tree.tag_order, reorder: true)
8
+ Tagmv::Filesystem.new(fs_options).transfer
18
9
  end
19
10
  end
20
11
 
12
+ def move_new_files
13
+ tree.entries << Entry.new(options)
14
+ fs_options = options.merge(tag_order: tree.tag_order, reorder: false)
15
+ Tagmv::Filesystem.new(fs_options).transfer
16
+ end
17
+
21
18
  def run
22
- @opts = Tagmv::Config.new.load
23
- update_tree
24
- move_files
19
+ reorder_files unless options[:skip_reorder]
20
+ move_new_files unless options[:files].empty?
25
21
  Tagmv::PrunePath.prune_tag_dirs
26
22
  end
23
+
24
+ private
25
+ def tree
26
+ @tree ||= Tagmv::Tree.scan_tree_entries
27
+ end
28
+
29
+ def options
30
+ @options ||= Tagmv::Options.new.options
31
+ end
27
32
  end
28
33
  end
data/lib/tagmv/tree.rb CHANGED
@@ -22,14 +22,20 @@ module Tagmv
22
22
 
23
23
  def self.false_tag_regex
24
24
  # detect when there's a false tag i.e. tag2. in path/to/tag1./not_a_tag/tag2./
25
- /\/.+\.\/[^.]+\/.+\./
25
+ /\/.+-\/[^-]+\/.+-/
26
+ #/\/(.*[^-]\/|[^\/]{0,1}?-)/
26
27
  end
28
+
27
29
  def self.tags_in_path_regex
28
- /\/\K.+?(?=\.\/)/
30
+ /[^(\.|\-)\/]\K.+?(?=\-\/)/
29
31
  end
30
32
 
31
33
  def self.path_has_file_regex
32
- /#{tags_in_path_regex}.*[^\.]$/
34
+ /#{tags_in_path_regex}.*[^\-]$/
35
+ end
36
+
37
+ def self.file_in_tag_dir
38
+ /.+(\-\/[^\/]+)$/
33
39
  end
34
40
 
35
41
  def self.tags(file)
@@ -37,22 +43,12 @@ module Tagmv
37
43
  file[Filesystem.root.length..-1].scan(tags_in_path_regex).reject {|x| x =~ /\//}
38
44
  end
39
45
 
40
- def self.empty_dirs
41
- files = Find.find(Filesystem.root).select {|x| x =~ path_has_file_regex }
42
- tree = Tree.new
43
- files.map do |file|
44
- next if file =~ false_tag_regex
45
- tree.with(files: [file], tags: tags(file))
46
- end
47
- tree
48
- end
49
-
50
46
  def self.scan_tree_entries
51
- files = Find.find(Filesystem.root).select {|x| x =~ path_has_file_regex }
47
+ files = Find.find(Filesystem.root).select {|x| x =~ path_has_file_regex }.select {|x| x =~ file_in_tag_dir }
52
48
  tree = Tree.new
53
- files.map do |file|
54
- next if file =~ /\/.+\.\/[^.]+\/.+\./ # break when /dev./oh/blah./foo
55
- tree.with(files: [file], tags: tags(file))
49
+ files.each do |file|
50
+ next if file =~ false_tag_regex # break when /dev./oh/blah./foo
51
+ tree.entries << Entry.new(files: [file], tags: tags(file))
56
52
  end
57
53
  tree
58
54
  end
@@ -62,12 +58,15 @@ module Tagmv
62
58
  # {"dev."=>{"book."=>{"javascript."=>{"Secrets_of_the_Javascript_Ninja.pdf"=>{}}, "ruby."=>{"rails_antipatterns.pdf"=>{}}}, "ruby."=>{"oh"=>{}, "tagmv"=>{}}}}
63
59
  def self.scan_tree_hash
64
60
  Dir.chdir(Filesystem.root)
65
- Dir["**/**./*"].inject({}) do |hash,path|
61
+
62
+ # reject /dev-/-, /dev-/j-/ and /dev-/notag/tag-
63
+ paths = Dir["**/*"].delete_if {|x| /\/(.*[^-]\/|[^\/]{0,1}?-)/ =~ x}
64
+ paths.inject({}) do |hash,path|
66
65
  tree = hash
67
66
  path.split("/").each do |n|
68
67
  tree[n] ||= {}
69
68
  tree = tree[n]
70
- break if n[-1] != "."
69
+ break if n[-1] != "-"
71
70
  end
72
71
  hash
73
72
  end
data/lib/tagmv/version.rb CHANGED
@@ -1,3 +1,5 @@
1
1
  module Tagmv
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
+ HOMEPAGE = "https://github.com/foucist/tagmv"
4
+ AUTHORS = ["James Robey"]
3
5
  end
data/tagmv.gemspec CHANGED
@@ -6,11 +6,11 @@ require 'tagmv/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "tagmv"
8
8
  spec.version = Tagmv::VERSION
9
- spec.authors = ["James Robey"]
9
+ spec.authors = Tagmv::AUTHORS
10
10
  spec.email = ["james.robey+tagmv@gmail.com"]
11
11
  spec.summary = %q{Tag your files by moving them into a tree-like tag structure}
12
12
  spec.description = %q{Moves your files into directories that represent tags, these tags are kept organized as a hierarchy according to tag counts}
13
- spec.homepage = "https://github.com/foucist/tagmv/"
13
+ spec.homepage = Tagmv::HOMEPAGE
14
14
  spec.license = 'MIT'
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tagmv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Robey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-23 00:00:00.000000000 Z
11
+ date: 2019-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -114,12 +114,13 @@ files:
114
114
  - lib/tagmv/config.rb
115
115
  - lib/tagmv/entry.rb
116
116
  - lib/tagmv/filesystem.rb
117
+ - lib/tagmv/options.rb
117
118
  - lib/tagmv/prune_path.rb
118
119
  - lib/tagmv/runner.rb
119
120
  - lib/tagmv/tree.rb
120
121
  - lib/tagmv/version.rb
121
122
  - tagmv.gemspec
122
- homepage: https://github.com/foucist/tagmv/
123
+ homepage: https://github.com/foucist/tagmv
123
124
  licenses:
124
125
  - MIT
125
126
  metadata: {}
@@ -139,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
140
  version: '0'
140
141
  requirements: []
141
142
  rubyforge_project:
142
- rubygems_version: 2.4.8
143
+ rubygems_version: 2.7.7
143
144
  signing_key:
144
145
  specification_version: 4
145
146
  summary: Tag your files by moving them into a tree-like tag structure