lazy_rotator 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d56a9409316a9c515cacc6fb2ccce23d196236b205b70c223c27b52809d5b2cc
4
+ data.tar.gz: e0dfec11ffb6830ef9e6940279849f6ac993b94d4916001ad23ae8ca93a654f3
5
+ SHA512:
6
+ metadata.gz: 9f7c200b136bd0f401822ead91a808e09c835890e26b24a1332207d344109d2ff401a8d5e8ff0b8e98feebba8fa83c0762c91a1e533d03f9b85dcd865571c59e
7
+ data.tar.gz: 6a491b1b0277f6a8390c0d981f0fe524b145decde8a489e0f37e64d8cdc1917dfa93db9594675df88fb959bf8b160c68f75a6547fb65589a2dfdc651ad52b0c8
@@ -0,0 +1,16 @@
1
+ .DS_Store
2
+ /.bundle/
3
+ /.ruby-version
4
+ /.yardoc
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
11
+ /vendor/ruby
12
+
13
+ /Gemfile.lock
14
+
15
+ # rspec failure tracking
16
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format Fuubar
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,15 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.2
3
+
4
+ Metrics/BlockLength:
5
+ Exclude:
6
+ - 'spec/**/*'
7
+
8
+ Metrics/LineLength:
9
+ Exclude:
10
+ - 'lazy_rotator.gemspec'
11
+ - 'spec/**/*'
12
+
13
+ Style/MutableConstant:
14
+ Exclude:
15
+ - 'lib/lazy_rotator/version.rb'
@@ -0,0 +1,19 @@
1
+ # Change Log
2
+
3
+ ## master (unreleased)
4
+
5
+ ### New features
6
+
7
+ - N/A
8
+
9
+ ### Bug fixes
10
+
11
+ - N/A
12
+
13
+ ### Changes
14
+
15
+ - N/A
16
+
17
+ ## [0.1.0 (2018-08-07)](https://github.com/jlw/lazy_rotator/releases/tag/v0.1.0)
18
+
19
+ - First release
@@ -0,0 +1,34 @@
1
+ # Contributing
2
+
3
+ If you discover issues, have ideas for improvements or new features, please report them to the [issue tracker][1] of the repository or submit a pull request. Please, try to follow these guidelines when you do so.
4
+
5
+ ## Issue reporting
6
+
7
+ - Check that the issue has not already been reported.
8
+ - Check that the issue has not already been fixed in the latest code (a.k.a. `master`).
9
+ - Be clear, concise and precise in your description of the problem.
10
+ - Open an issue with a descriptive title and a summary in grammatically correct, complete sentences.
11
+ - Include any relevant code to the issue summary.
12
+
13
+ ## Pull requests
14
+
15
+ - Read [how to properly contribute to open source projects on GitHub][2].
16
+ - Fork the project.
17
+ - Use a topic/feature branch to easily amend a pull request later, if necessary.
18
+ - Write [good commit messages][3].
19
+ - Use the same coding conventions as the rest of the project.
20
+ - Commit and push until you are happy with your contribution.
21
+ - If your change has a corresponding open GitHub issue, prefix the commit message with `[Fix #github-issue-number]`.
22
+ - Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
23
+ - Add an entry to the [Change Log](CHANGELOG.md) accordingly.
24
+ - Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
25
+ - Make sure the test suite is passing for all supported Ruby versions: `./all_rubies bundle && ./all_rubies spec`.
26
+ - Make sure the code you wrote doesn't produce RuboCop offenses `bundle exec rubocop`.
27
+ - [Squash related commits together][5].
28
+ - Open a [pull request][4] that relates to _only_ one subject with a clear title and description in grammatically correct, complete sentences.
29
+
30
+ [1]: https://github.com/jlw/lazy_rotator/issues
31
+ [2]: http://gun.io/blog/how-to-github-fork-branch-and-pull-request
32
+ [3]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
33
+ [4]: https://help.github.com/articles/about-pull-requests
34
+ [5]: http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in lazy_rotator.gemspec
8
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org>
@@ -0,0 +1,43 @@
1
+ # LazyRotator
2
+
3
+ Tie log (or other file) rotation to the (un-scheduled?) execution of code. The _raison d'étre_ for this gem is that I'm too lazy to clear out test and development logs manually and am too anal-retentive to be happy with large log files accumulating in my various project directories.
4
+
5
+ On those rare occasions when I do want to look at a log file in my development environment, I don't want to waste time skipping past megabytes of older log entries. On the other hand, I might have restarted my app server or run tests (maybe a different set) again before deciding to look at the logs, so I don't want to simply truncate the log files on each run - keeping a few very recent files around seems to be a useful compromise.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'lazy_rotator', group: %i(development test)
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install lazy_rotator
22
+
23
+ ## Usage
24
+
25
+ For a Rails app, add the following to `config/application.rb`:
26
+
27
+ ```ruby
28
+ if defined?(LazyRotator) && (Rails.env.test? || Rails.env.development?)
29
+ LazyRotator.rotate(File.expand_path("../log/#{Rails.env}.log", __dir__))
30
+ end
31
+ ```
32
+
33
+ _Note:_ you will probably need to update your `.gitignore` file to match `/log/*.log*` - that trailing `*` will catch the rotated files.
34
+
35
+ Set the number of copies to keep (the default is 5):
36
+ ```ruby
37
+ LazyRotator.rotate('path/to/log', 20)
38
+ ```
39
+
40
+
41
+ ## Contributing
42
+
43
+ [Bug reports and pull requests are welcome.](CONTRIBUTING.md)
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,44 @@
1
+ #!/bin/bash
2
+
3
+ versions=('2.2.10' '2.3.7' '2.4.4' '2.5.1')
4
+
5
+ switcher=`which rbenv`
6
+ if [[ $switcher = *[!\ ]* ]]; then
7
+ verb="local"
8
+ else
9
+ switcher=`which rvm`
10
+ if [[ $switcher = *[!\ ]* ]]; then
11
+ verb="use"
12
+ else
13
+ echo "Please install rbenv or rvm"
14
+ exit 1
15
+ fi
16
+ fi
17
+
18
+ case "$1" in
19
+ bundle)
20
+ for version in ${versions[@]}
21
+ do
22
+ echo "Bundle for Ruby $version"
23
+ eval "$switcher $verb $version"
24
+ gem list --local bundler | grep bundler || gem install bundler --no-ri --no-rdoc
25
+ bundle install --path vendor
26
+ bundle update
27
+ done
28
+ ;;
29
+
30
+ spec)
31
+ for version in ${versions[@]}
32
+ do
33
+ echo "Run specs with Ruby $version"
34
+ eval "$switcher $verb $version"
35
+ bundle exec rspec spec
36
+ done
37
+ ;;
38
+
39
+ *)
40
+ echo $"Usage: $0 {bundle|spec}"
41
+ exit 1
42
+ esac
43
+
44
+ exit 0
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'lazy_rotator'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'lazy_rotator/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'lazy_rotator'
9
+ spec.version = LazyRotator::VERSION
10
+ spec.authors = ['Jeremy Weathers']
11
+ spec.email = ['jeremy@codekindly.com']
12
+
13
+ spec.summary = 'Lazily rotate log files'
14
+ spec.description = "Tie log (or other file) rotation to the (un-scheduled?) execution of code. The raison d'étre for this gem is that I'm too lazy to clear out test and development logs manually and am too anal-retentive to be happy with large log files accumulating in my various project directories."
15
+ spec.homepage = 'https://github.com/jlw/lazy_rotator'
16
+ spec.license = 'Unlicense'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ spec.bindir = 'exe'
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ['lib']
24
+
25
+ spec.required_ruby_version = '>= 2.2.0'
26
+
27
+ spec.add_development_dependency 'bundler', '~> 1.16'
28
+ spec.add_development_dependency 'fuubar'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+ spec.add_development_dependency 'rspec', '~> 3.0'
31
+ spec.add_development_dependency 'rubocop'
32
+ spec.add_development_dependency 'simplecov'
33
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lazy_rotator/file'
4
+ require 'lazy_rotator/set'
5
+ require 'lazy_rotator/version'
6
+
7
+ # Rotate a set of files
8
+ module LazyRotator
9
+ def self.rotate(file_name, retention_limit = 5)
10
+ Set.new(file_name, retention_limit).process
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'file/undetermined'
4
+ require_relative 'file/delete'
5
+ require_relative 'file/ignore'
6
+ require_relative 'file/rename'
7
+ require_relative 'file/touch'
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LazyRotator
4
+ module File
5
+ # Removes files that have met the current retention limit
6
+ class Delete < Undetermined
7
+ def process
8
+ ::File.delete file_name
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LazyRotator
4
+ module File
5
+ # Skips processing on a file that does not need to be renamed or deleted
6
+ # during the current rotation (this is an edge case suggesting a previous
7
+ # error or manual deletion of files)
8
+ class Ignore < Undetermined
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LazyRotator
4
+ module File
5
+ # Moves a file along in the rotation (assuming it should still be kept)
6
+ class Rename < Undetermined
7
+ attr_reader :new_number
8
+
9
+ def initialize(file_name, new_number)
10
+ @file_name = file_name
11
+ @new_number = new_number
12
+ end
13
+
14
+ def file_name_without_number
15
+ @file_name_without_number ||= begin
16
+ m = Regexp.new("^(.+)\\.#{number}$").match(::File.basename(file_name))
17
+ return file_name unless m
18
+ ::File.join(::File.dirname(file_name), m[1])
19
+ end
20
+ end
21
+
22
+ def new_file_name
23
+ file_name_without_number + ".#{new_number}"
24
+ end
25
+
26
+ def process
27
+ ::File.rename(file_name, new_file_name)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LazyRotator
4
+ module File
5
+ # Ensure the initial file is in place
6
+ class Touch < Undetermined
7
+ def process
8
+ return unless number.zero?
9
+ ::FileUtils.touch file_name
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LazyRotator
4
+ module File
5
+ # The placeholder for a file before determining the correct action as part
6
+ # of the current rotation process
7
+ class Undetermined
8
+ attr_reader :file_name
9
+
10
+ def initialize(file_name)
11
+ @file_name = file_name.to_s
12
+ end
13
+
14
+ def number
15
+ @number ||= self.class.file_number(file_name)
16
+ end
17
+
18
+ def process; end
19
+
20
+ # rubocop:disable Metrics/AbcSize
21
+ def ==(other)
22
+ return false if self.class.name != other.class.name
23
+ return false if number != other.number
24
+ return false if file_name != other.file_name
25
+ return true unless respond_to?(:new_number)
26
+ return false if new_number != other.new_number
27
+ true
28
+ end
29
+ # rubocop:enable Metrics/AbcSize
30
+
31
+ def <=>(other)
32
+ return number <=> other.number unless number == other.number
33
+ file_name <=> other.file_name
34
+ end
35
+
36
+ def self.file_number(file_name)
37
+ file_name.to_s.split('.').last.to_i
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LazyRotator
4
+ # Collects rotated/to-rotate files and decides what to do with each
5
+ class Set
6
+ include Enumerable
7
+
8
+ attr_reader :files
9
+
10
+ def initialize(file_name, retention_limit)
11
+ # reverse the prepared set so that rotated naming works correctly
12
+ # if I rename '1' to '2' and then '2' to '3', etc. I lose those files
13
+ @files = self.class.prepare_files(file_name, retention_limit).reverse
14
+ end
15
+
16
+ def each(&block)
17
+ @files.each(&block)
18
+ end
19
+
20
+ def process
21
+ map(&:process)
22
+ end
23
+
24
+ class << self
25
+ def file_regexp(file_name)
26
+ Regexp.new(Regexp.quote(file_name) + '(\\.\\d+)?$')
27
+ end
28
+
29
+ # return a set of collected files with correct processing decisions
30
+ def prepare_files(file_name, retention_limit)
31
+ raw_files = collect_files(file_name.to_s)
32
+ prepared_files = [File::Touch.new(file_name)]
33
+ delete_after = retention_limit - 1
34
+ next_number = 1
35
+ raw_files.each do |file|
36
+ prepared_files << prepare_file(file, delete_after, next_number)
37
+ next_number += 1
38
+ end
39
+ prepared_files
40
+ end
41
+
42
+ private
43
+
44
+ # find all matching files that should be processed as part of the rotation
45
+ def collect_files(file_name)
46
+ regexp = file_regexp(file_name)
47
+ naive_list = Dir.glob(file_name + '*')
48
+ file_list = naive_list.select { |f| regexp.match(f) }
49
+ file_list.map { |f| File::Undetermined.new(f) }.sort
50
+ end
51
+
52
+ def prepare_file(file, delete_after, next_number)
53
+ corrected_number = next_number - 1
54
+ if corrected_number > delete_after
55
+ File::Delete.new(file.file_name)
56
+ elsif file.number == next_number
57
+ File::Ignore.new(file.file_name)
58
+ else
59
+ File::Rename.new(file.file_name, next_number)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LazyRotator
4
+ VERSION = '0.1.0'
5
+ end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lazy_rotator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jeremy Weathers
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-08-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: fuubar
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Tie log (or other file) rotation to the (un-scheduled?) execution of
98
+ code. The raison d'étre for this gem is that I'm too lazy to clear out test and
99
+ development logs manually and am too anal-retentive to be happy with large log files
100
+ accumulating in my various project directories.
101
+ email:
102
+ - jeremy@codekindly.com
103
+ executables: []
104
+ extensions: []
105
+ extra_rdoc_files: []
106
+ files:
107
+ - ".gitignore"
108
+ - ".rspec"
109
+ - ".rubocop.yml"
110
+ - CHANGELOG.md
111
+ - CONTRIBUTING.md
112
+ - Gemfile
113
+ - LICENSE
114
+ - README.md
115
+ - Rakefile
116
+ - all_rubies
117
+ - bin/console
118
+ - bin/setup
119
+ - lazy_rotator.gemspec
120
+ - lib/lazy_rotator.rb
121
+ - lib/lazy_rotator/file.rb
122
+ - lib/lazy_rotator/file/delete.rb
123
+ - lib/lazy_rotator/file/ignore.rb
124
+ - lib/lazy_rotator/file/rename.rb
125
+ - lib/lazy_rotator/file/touch.rb
126
+ - lib/lazy_rotator/file/undetermined.rb
127
+ - lib/lazy_rotator/set.rb
128
+ - lib/lazy_rotator/version.rb
129
+ homepage: https://github.com/jlw/lazy_rotator
130
+ licenses:
131
+ - Unlicense
132
+ metadata: {}
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: 2.2.0
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 2.7.6
150
+ signing_key:
151
+ specification_version: 4
152
+ summary: Lazily rotate log files
153
+ test_files: []