tagmv 0.0.2 → 0.0.3

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.
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