mez 0.8.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.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/bin/mez +33 -0
  3. data/lib/mez/VERSION.rb +3 -0
  4. data/lib/mez.rb +116 -0
  5. metadata +89 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9229e10affa135c3ce6542006affa29d1cf148da
4
+ data.tar.gz: e0559af63b3b33677d6b907f70e4e8f971d42cc2
5
+ SHA512:
6
+ metadata.gz: 98b194786f55dfed6770da15fcb8d2c01fcf974538503aea4799a8a34ed7ea34b9f9bb33d4edfc72898a7c5573f43b3dc445daec8839775cc78c3d1f0b8aee06
7
+ data.tar.gz: b00f64269b83b2a72202fac60890946dec3719d1d2786f370672bf999f05458bb5006ed153f269204fb02ac8a08126580a21aeb34e22a93b975bf6057ad448dc
data/bin/mez ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+ require 'mez'
3
+
4
+ unless File.exist?(File.join(Mez::APP_DIR, 'folders.json'))
5
+ os_prefix = OS.windows? ? 'c:/files/' : '~/'
6
+ puts 'You are missing your configuration file!'
7
+ puts "It should be at #{Mez::CONFIG}, and should look like this:
8
+
9
+ {
10
+ \"projects\": [
11
+ \"#{os_prefix}work projects\",
12
+ \"#{os_prefix}personal projects\" ],
13
+ \"books\": [
14
+ \"#{os_prefix}fiction\",
15
+ \"#{os_prefix}nonfiction\" ]
16
+ }"
17
+ exit
18
+ end
19
+
20
+ total_size = 0
21
+ total_difference = 0
22
+
23
+ Mez.intro_line
24
+ JSON.parse(File.read(Mez::CONFIG)).each do |name, folderset|
25
+ size = Mez.setsize(folderset)
26
+ Mez.update(name, size)
27
+ total_size += size
28
+ yesterday = Mez.yesterday_size(name)
29
+ difference = yesterday ? size - yesterday : 0
30
+ total_difference += difference
31
+ Mez.report(name, size, difference)
32
+ end
33
+ Mez.closing_line(total_size, total_difference)
@@ -0,0 +1,3 @@
1
+ module Mez
2
+ VERSION = '0.8.1'.freeze
3
+ end
data/lib/mez.rb ADDED
@@ -0,0 +1,116 @@
1
+ # Configuration and the SQLite database are stored in ~/.mez/ on macOS
2
+ # and Linux, and in %localappdata%/mez on Windows.
3
+ require 'sqlite3'
4
+ require 'date'
5
+ require 'os'
6
+ require 'json'
7
+ require 'fileutils'
8
+ require 'win32ole' if OS.windows?
9
+
10
+ module Mez
11
+ APP_DIR = if OS.windows?
12
+ File.join(File.expand_path('~'), 'appdata', 'local', 'mez')
13
+ else
14
+ File.join(File.expand_path('~'), '.mez')
15
+ end
16
+ CONFIG = File.join(APP_DIR, 'folders.json')
17
+ DB = if File.exist?(File.join(APP_DIR, 'folders.db'))
18
+ SQLite3::Database.new(File.join(APP_DIR, 'folders.db'))
19
+ else
20
+ FileUtils.mkdir_p(APP_DIR) unless File.exist?(APP_DIR)
21
+ db = SQLite3::Database.new(File.join(APP_DIR, 'folders.db'))
22
+ db.execute('CREATE TABLE folders (name string, date string, size int,
23
+ PRIMARY KEY ("name", "date"))')
24
+ db
25
+ end
26
+
27
+ # Calculates the size of a folder and its contents as an integer.
28
+ # On Windows, uses the Win32 API, which caches folder information and makes
29
+ # repeated calls to this function very fast. On other systems, sums individual
30
+ # file sizes.
31
+ #
32
+ # @param folder [String] a path to a folder, eg '~/books' or 'c:\books'
33
+ # @return [Integer] the folder's size in bytes
34
+ def self.folder_size(folder)
35
+ if OS.windows?
36
+ # Much faster for repeated calls than calculating sizes in Ruby.
37
+ WIN32OLE.new('Scripting.FileSystemObject').getFolder(folder).size.to_i
38
+ else
39
+ size = 0
40
+ Dir.glob(File.join(folder, '**', '*')) { |file| size += File.size(file) }
41
+ size
42
+ end
43
+ end
44
+
45
+ # Uses commas as separators to make large numbers human-readable.
46
+ #
47
+ # @param num [Integer] any integer, eg -48151
48
+ # @return [String] a human readable number, eg "-48,151"
49
+ def self.humanise(num)
50
+ (prefix(num) == '-' ? '-' : '') + num
51
+ .abs
52
+ .to_s
53
+ .split('')
54
+ .reverse
55
+ .each_slice(3)
56
+ .map(&:join)
57
+ .join(',')
58
+ .reverse
59
+ end
60
+
61
+ # Provide a "+" or "-" prefix based on whether `n` is positive or negative.
62
+ #
63
+ # @param n [Number]
64
+ # @return [String] "+" or "-"
65
+ def self.prefix(n)
66
+ n >= 0 ? '+' : '-'
67
+ end
68
+
69
+ # Format a number for the 'change' column, meaning a + or - prefix and a
70
+ # number in bytes converted to a comma-separated number in IEC megabytes.
71
+ #
72
+ # @param n [Integer] size differential in bytes
73
+ # @return [String] "+48,151"
74
+ def self.difference_report(n)
75
+ n.zero? ? '' : prefix(n) + humanise(n.abs / 1_000_000)
76
+ end
77
+
78
+ def self.yesterday_size(name)
79
+ DB.get_first_value('SELECT size FROM folders
80
+ WHERE name = ? AND date <> ?
81
+ ORDER BY date DESC
82
+ LIMIT 1', name, Date.today.to_s)
83
+ end
84
+
85
+ def self.report(name, size, difference)
86
+ puts name.ljust(54) +
87
+ humanise(size / 1_000_000).rjust(10) +
88
+ difference_report(difference).rjust(16)
89
+ end
90
+
91
+ def self.intro_line
92
+ puts "\nFOLDERSET".ljust(56) + 'SIZE (MB)' + 'CHANGE (MB)'.rjust(16)
93
+ puts('-' * 80)
94
+ end
95
+
96
+ # Take an array of folder names, and return their total size in bytes.
97
+ #
98
+ # @param [Array<String>] array of folder names
99
+ # @return [Integer] total size of all folders and their contents
100
+ def self.setsize(folderset)
101
+ folderset.reduce(0) { |acc, elem| acc + Mez.folder_size(elem) }
102
+ end
103
+
104
+ def self.closing_line(total_size, total_difference)
105
+ puts('-' * 80)
106
+ puts 'TOTAL SIZE: ' +
107
+ humanise(total_size / 1_000_000) +
108
+ ('TOTAL CHANGE: ' + humanise(total_difference / 1_000_000)).rjust(59)
109
+ end
110
+
111
+ def self.update(name, size)
112
+ DB.execute('INSERT OR REPLACE INTO folders
113
+ (name, size, date)
114
+ VALUES (?,?,?)', name, size, Date.today.to_s)
115
+ end
116
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mez
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.1
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Plant
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: os
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.9.6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.9.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.5'
55
+ description:
56
+ email: ryan@ryanplant.net
57
+ executables:
58
+ - mez
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - bin/mez
63
+ - lib/mez.rb
64
+ - lib/mez/VERSION.rb
65
+ homepage: https://github.com/ryantriangles/mez
66
+ licenses:
67
+ - MIT
68
+ metadata: {}
69
+ post_install_message: Please configure your folders.json!
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ requirements: []
84
+ rubyforge_project:
85
+ rubygems_version: 2.5.1
86
+ signing_key:
87
+ specification_version: 4
88
+ summary: A CLI utility to track directory sizes over time
89
+ test_files: []