ignorance 0.0.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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +151 -0
- data/Rakefile +1 -0
- data/ignorance.gemspec +25 -0
- data/lib/ignorance.rb +85 -0
- data/lib/ignorance/git_ignore_file.rb +33 -0
- data/lib/ignorance/hg_ignore_file.rb +16 -0
- data/lib/ignorance/ignore_file.rb +96 -0
- data/lib/ignorance/project_oriented_vcs.rb +14 -0
- data/lib/ignorance/svn_ignore_file.rb +13 -0
- data/lib/ignorance/version.rb +3 -0
- data/spec/ignorefile_helpers.rb +25 -0
- data/spec/io_helpers.rb +32 -0
- data/spec/lib/ignorance/git_ignore_file_spec.rb +31 -0
- data/spec/lib/ignorance/hg_ignore_file_spec.rb +14 -0
- data/spec/lib/ignorance/ignore_file_spec.rb +11 -0
- data/spec/lib/ignorance/svn_ignore_file_spec.rb +14 -0
- data/spec/lib/ignorance_spec.rb +49 -0
- data/spec/shared_examples/for_ignorance.rb +93 -0
- data/spec/shared_examples/for_ignore_files.rb +147 -0
- data/spec/shared_examples/for_project_oriented_vcs.rb +26 -0
- data/spec/spec_helper.rb +16 -0
- metadata +145 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Joel Helbling
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
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
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
# Ignorance
|
2
|
+
|
3
|
+
Ensures specified files are ignored by Git, Mercurial or SVN.
|
4
|
+
|
5
|
+
## Use Case
|
6
|
+
|
7
|
+
You've created a utility to be used by others' projects which generates
|
8
|
+
or uses files and directories which ought not be committed/pushed/shared
|
9
|
+
with the world.
|
10
|
+
|
11
|
+
Ignorance helps your code be considerate of its users by protecting
|
12
|
+
their sensitive information.
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
gem 'ignorance'
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
|
26
|
+
$ gem install ignorance
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
If you'd like to warn users and fellow developers to add certain artifacts
|
31
|
+
to the project's ignore file, you can include this somewhere in your runtime:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
include Ignorance
|
35
|
+
|
36
|
+
advise_ignorance '.myfile'
|
37
|
+
```
|
38
|
+
|
39
|
+
Assuming those files are not in the project's .gitignore file, when
|
40
|
+
the code is run, your program will output the following to STDERR
|
41
|
+
(but not halt):
|
42
|
+
|
43
|
+
```
|
44
|
+
WARNING: please add ".myfile" to this project's .gitignore file!
|
45
|
+
```
|
46
|
+
|
47
|
+
If ignoring those files is really critical, you can halt with an exception:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
guard_ignorance 'mydir/'
|
51
|
+
```
|
52
|
+
|
53
|
+
You can even prompt the user, offering to automatically add the pertinent
|
54
|
+
files to the ignore file:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
negotiate_ignorance 'some_file.md'
|
58
|
+
```
|
59
|
+
|
60
|
+
And finally, if ignorance is absolutely critical, you can silently add
|
61
|
+
tokens to the project's ignore file:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
guarantee_ignorance! 'mydir/'
|
65
|
+
```
|
66
|
+
|
67
|
+
You can also use Ignorance directly (with out including the module).
|
68
|
+
Shorter method names are provided for that purpose:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
Ignorance.advise '.myfile'
|
72
|
+
Ignorance.guard 'some_other_file.txt'
|
73
|
+
Ignorance.negotiate 'family_phone_numbers.yaml'
|
74
|
+
Ignorance.guarantee! 'bank_login.cfg'
|
75
|
+
```
|
76
|
+
|
77
|
+
## When Ignorance Works
|
78
|
+
|
79
|
+
Ignorance works on the ignore files of any and all detected repository types.
|
80
|
+
If .git is present, .gitignore is managed. If .hg then .hgignore,
|
81
|
+
if .svn, .svnignore. For Git and Mercurial, parent directories will also
|
82
|
+
be searched for a repository root.
|
83
|
+
|
84
|
+
Ignorance does nothing when one of two conditions exist:
|
85
|
+
|
86
|
+
1. All specified tokens are already ignored
|
87
|
+
2. The current directory is not within a repository
|
88
|
+
|
89
|
+
Ignorance's repo detection is based on the current working directory (e.g.
|
90
|
+
Dir.getwd, usually the directory where the code was launched). It presumes
|
91
|
+
the common dev-time situation wherein a program is launched from within its
|
92
|
+
project dir.
|
93
|
+
|
94
|
+
This means that if your code uses Ignorance, and others use your code, repo
|
95
|
+
and ignore file detection will happen relative to their project directory.
|
96
|
+
|
97
|
+
## Adding a Comment
|
98
|
+
|
99
|
+
The #negotiate and #guarantee! methods (and their longer counterparts)
|
100
|
+
accept an optional comment parameter:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
negotiate_ignorance 'api_token.yml', 'added by HandyBankUtil'
|
104
|
+
```
|
105
|
+
|
106
|
+
This will add the following to the ignore file (assuming 'api_token.yml'
|
107
|
+
wasn't already ignored):
|
108
|
+
|
109
|
+
```
|
110
|
+
# added by HandyBankUtil
|
111
|
+
api_token.yml
|
112
|
+
|
113
|
+
```
|
114
|
+
|
115
|
+
If the supplied comment was already in the ignore file (suppose you
|
116
|
+
negotiated several tokens with the same comment), the new token will be
|
117
|
+
added to the bottom of that section. So if the ignore file already had
|
118
|
+
this:
|
119
|
+
|
120
|
+
```
|
121
|
+
# added by HandyBankUtil
|
122
|
+
secret_info.txt
|
123
|
+
|
124
|
+
```
|
125
|
+
|
126
|
+
The above example would result in this in the ignore file:
|
127
|
+
|
128
|
+
```
|
129
|
+
# added by HandyBankUtil
|
130
|
+
secret_info.txt
|
131
|
+
api_token.yml
|
132
|
+
|
133
|
+
```
|
134
|
+
|
135
|
+
## Contributing
|
136
|
+
|
137
|
+
1. Fork it
|
138
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
139
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
140
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
141
|
+
5. Create new Pull Request
|
142
|
+
|
143
|
+
## Do you love Ignorance, and want to make it even better?
|
144
|
+
|
145
|
+
Here's some stuff I ain't figured out yet:
|
146
|
+
|
147
|
+
- *Support for globs & regexes*: If you `gaurd_ignorance 'myfile.private'` and
|
148
|
+
the ignore file contains a glob or regex which would cause that to be ignored,
|
149
|
+
Ignorance will raise an error anyway.
|
150
|
+
- *Support for other version control systems.* Visual SourceSafe can't use
|
151
|
+
Ignorance. Does that seem right to you?
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/ignorance.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ignorance/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "ignorance"
|
8
|
+
gem.version = Ignorance::VERSION
|
9
|
+
gem.authors = ["Joel Helbling"]
|
10
|
+
gem.email = ["joel@joelhelbling.com"]
|
11
|
+
gem.description = %q{Ensures specified files are ignored by Git, Mercurial or SVN.}
|
12
|
+
gem.summary = %q{Ignorance helps your code be considerate of its users by protecting sensitive information from version control.}
|
13
|
+
gem.homepage = "http://github.com/joelhelbling/ignorance"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency 'highline', '~> 1.6.15'
|
21
|
+
|
22
|
+
gem.add_development_dependency 'rspec', '~> 2.12.0'
|
23
|
+
gem.add_development_dependency 'fakefs', '~> 0.4.2'
|
24
|
+
gem.add_development_dependency 'pry', '~> 0.9.11.4'
|
25
|
+
end
|
data/lib/ignorance.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'highline'
|
2
|
+
require 'ignorance/version'
|
3
|
+
|
4
|
+
require 'ignorance/git_ignore_file'
|
5
|
+
require 'ignorance/hg_ignore_file'
|
6
|
+
require 'ignorance/svn_ignore_file'
|
7
|
+
|
8
|
+
module Ignorance
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def advise(token)
|
12
|
+
active_ignore_files.each do |ignore_file|
|
13
|
+
warning token, ignore_file unless ignore_file.ignored?(token)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def guard(token)
|
18
|
+
active_ignore_files.each do |ignore_file|
|
19
|
+
unless ignore_file.ignored?(token)
|
20
|
+
raise IgnorefileError.new "Please add \"#{token}\" to this project's #{ignore_file.name} file!"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def negotiate(token, comment=nil)
|
26
|
+
active_ignore_files.each do |ignore_file|
|
27
|
+
unless ignore_file.ignored?(token)
|
28
|
+
msg = "would you like me to add #{token} to this project's #{ignore_file.name} file automatically?"
|
29
|
+
if agree? msg
|
30
|
+
guarantee! token, comment
|
31
|
+
puts "Added \"#{token}\" to this project's #{ignore_file.name} file."
|
32
|
+
else
|
33
|
+
warning token, ignore_file
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def guarantee!(token, comment=nil)
|
40
|
+
active_ignore_files.each do |ignore_file|
|
41
|
+
unless ignore_file.ignored?(token)
|
42
|
+
ignore_file.ignore! token, comment
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def warning(token, ignore_file)
|
50
|
+
warn "WARNING: please add \"#{token}\" to this project's #{ignore_file.name} file!"
|
51
|
+
end
|
52
|
+
|
53
|
+
def active_ignore_files
|
54
|
+
ignore_files.select(&:its_a_repo?)
|
55
|
+
end
|
56
|
+
|
57
|
+
def ignore_files
|
58
|
+
[GitIgnoreFile.new, HgIgnoreFile.new, SvnIgnoreFile.new]
|
59
|
+
end
|
60
|
+
|
61
|
+
def agree?(msg)
|
62
|
+
HighLine.new.agree("#{msg} [Y]es/[n]o? ")
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
def advise_ignorance(token)
|
68
|
+
Ignorance.advise token, comment
|
69
|
+
end
|
70
|
+
|
71
|
+
def guard_ignorance(token)
|
72
|
+
Ignorance.guard token, comment
|
73
|
+
end
|
74
|
+
|
75
|
+
def negotiate_ignorance(token, comment=nil)
|
76
|
+
Ignorance.negotiate token, comment
|
77
|
+
end
|
78
|
+
|
79
|
+
def guarantee_ignorance!(token, comment=nil)
|
80
|
+
Ignorance.guarantee! token, comment
|
81
|
+
end
|
82
|
+
|
83
|
+
class IgnorefileError < IOError; end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'ignorance/ignore_file'
|
2
|
+
require 'ignorance/project_oriented_vcs'
|
3
|
+
|
4
|
+
module Ignorance
|
5
|
+
class GitIgnoreFile < IgnoreFile
|
6
|
+
attr_reader :ignore_file, :repo_dir
|
7
|
+
|
8
|
+
include ProjectOrientedVCS
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@ignore_file = '.gitignore'
|
12
|
+
@repo_dir = '.git'
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def ignored
|
18
|
+
(file_contents + user_ignore_file_contents).reject do |t|
|
19
|
+
t.match /^\#/
|
20
|
+
end.map(&:chomp)
|
21
|
+
end
|
22
|
+
|
23
|
+
def user_ignore_file_contents
|
24
|
+
File.exists?(user_ignore_file) ? File.readlines(user_ignore_file) : []
|
25
|
+
end
|
26
|
+
|
27
|
+
def user_ignore_file
|
28
|
+
@user_ignore_file ||= `git config --global --get core.excludesfile`.chomp
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'ignorance/ignore_file'
|
2
|
+
require 'ignorance/project_oriented_vcs'
|
3
|
+
|
4
|
+
module Ignorance
|
5
|
+
class HgIgnoreFile < IgnoreFile
|
6
|
+
attr_reader :ignore_file, :repo_dir
|
7
|
+
|
8
|
+
include ProjectOrientedVCS
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@ignore_file = '.hgignore'
|
12
|
+
@repo_dir = '.hg'
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Ignorance
|
2
|
+
class IgnoreFile
|
3
|
+
|
4
|
+
def name
|
5
|
+
ignore_file
|
6
|
+
end
|
7
|
+
|
8
|
+
def exists?
|
9
|
+
File.exists? ignore_file
|
10
|
+
end
|
11
|
+
|
12
|
+
def its_a_repo?
|
13
|
+
Dir.exists? repo_dir
|
14
|
+
end
|
15
|
+
|
16
|
+
def ignored?(token)
|
17
|
+
ignored.include? token
|
18
|
+
end
|
19
|
+
|
20
|
+
def included?(token)
|
21
|
+
file_contents.include? token
|
22
|
+
end
|
23
|
+
|
24
|
+
def ignore!(token, comment=nil)
|
25
|
+
return true if ignored?(token)
|
26
|
+
if comment
|
27
|
+
anchor = commentified comment
|
28
|
+
if included? anchor
|
29
|
+
insert_after anchor, token
|
30
|
+
else
|
31
|
+
append "\n"
|
32
|
+
append anchor
|
33
|
+
append token
|
34
|
+
end
|
35
|
+
else # There's no comment
|
36
|
+
append token
|
37
|
+
end
|
38
|
+
|
39
|
+
write_ignore_file
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def ignored
|
45
|
+
file_contents.reject{ |t| t.match /^\#/ }.map(&:chomp)
|
46
|
+
end
|
47
|
+
|
48
|
+
def file_contents
|
49
|
+
@file_contents ||= exists? ? File.readlines(ignore_file) : []
|
50
|
+
end
|
51
|
+
|
52
|
+
def insert_at(index, token)
|
53
|
+
file_contents.insert(index, token)
|
54
|
+
end
|
55
|
+
|
56
|
+
def append(token)
|
57
|
+
insert_at(file_contents.size, token)
|
58
|
+
end
|
59
|
+
|
60
|
+
def insert_after(anchor, token)
|
61
|
+
insert_index = file_contents.find_index(anchor) + 1
|
62
|
+
insert_index += 1 until here_is_good?(insert_index)
|
63
|
+
insert_at insert_index, token
|
64
|
+
end
|
65
|
+
|
66
|
+
def here_is_good?(insert_index)
|
67
|
+
at_maximum?(insert_index) || blank_line_at?(insert_index)
|
68
|
+
end
|
69
|
+
|
70
|
+
def at_maximum?(insert_index)
|
71
|
+
insert_index >= file_contents.size
|
72
|
+
end
|
73
|
+
|
74
|
+
def blank_line_at?(insert_index)
|
75
|
+
file_contents[insert_index].match(/^[\s\n]*$/)
|
76
|
+
end
|
77
|
+
|
78
|
+
def commentified(comment)
|
79
|
+
"# " + comment.gsub(/^\s*\#\s*/, '')
|
80
|
+
end
|
81
|
+
|
82
|
+
def printified(line)
|
83
|
+
line.chomp + "\n"
|
84
|
+
end
|
85
|
+
|
86
|
+
def write_ignore_file
|
87
|
+
File.open(ignore_file, 'w') do |fh|
|
88
|
+
file_contents.each do |line|
|
89
|
+
fh.write printified line
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Ignorance
|
2
|
+
module ProjectOrientedVCS
|
3
|
+
|
4
|
+
def its_a_repo?
|
5
|
+
path = Dir.getwd.scan(/\/[^\/]+/).map{|p| p[1..-1]}
|
6
|
+
repo_found = false
|
7
|
+
until (repo_found = Dir.exists?(File.join("/", path, @repo_dir))) || path.empty?
|
8
|
+
path.pop
|
9
|
+
end
|
10
|
+
repo_found
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module IgnorefileHelpers
|
2
|
+
|
3
|
+
def ignorefile_write(contents)
|
4
|
+
File.open(ignore_file, 'w') do |fh|
|
5
|
+
fh.write contents
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def ignorefile_lines
|
10
|
+
File.readlines(ignore_file)
|
11
|
+
end
|
12
|
+
|
13
|
+
def ignored_tokens
|
14
|
+
ignorefile_lines.map(&:chomp)
|
15
|
+
end
|
16
|
+
|
17
|
+
def ignorefile_contents
|
18
|
+
File.read(ignore_file)
|
19
|
+
end
|
20
|
+
|
21
|
+
def mk_repo_dir
|
22
|
+
Dir.mkdir repo_dir
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/spec/io_helpers.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
module IOHelpers
|
4
|
+
|
5
|
+
def output_from
|
6
|
+
$stdout = $stderr = fake_io
|
7
|
+
yield
|
8
|
+
fake_io.string
|
9
|
+
ensure
|
10
|
+
$stdout = STDOUT; $stderr = STDERR
|
11
|
+
end
|
12
|
+
|
13
|
+
def user_types(input, &block)
|
14
|
+
$stdin = StringIO.new input
|
15
|
+
output_from &block
|
16
|
+
ensure
|
17
|
+
$stdin = STDIN
|
18
|
+
end
|
19
|
+
|
20
|
+
def stdout_from(&block)
|
21
|
+
output_from &block
|
22
|
+
end
|
23
|
+
|
24
|
+
def stderr_from(&block)
|
25
|
+
output_from &block
|
26
|
+
end
|
27
|
+
|
28
|
+
def fake_io
|
29
|
+
@fake_io ||= StringIO.new
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ignorance/git_ignore_file'
|
3
|
+
|
4
|
+
module Ignorance
|
5
|
+
describe GitIgnoreFile, :fakefs do
|
6
|
+
|
7
|
+
let(:ignore_file) { '.gitignore' }
|
8
|
+
let(:repo_dir) { '.git' }
|
9
|
+
|
10
|
+
it_should_behave_like "an ignore file"
|
11
|
+
it_should_behave_like "a project-oriented VCS"
|
12
|
+
|
13
|
+
context "when the user's gitignore file includes the token" do
|
14
|
+
let(:token) { "foofile.md" }
|
15
|
+
let(:user_ignore_file) { '~/.gitignore' }
|
16
|
+
before do
|
17
|
+
ignorefile_write %w[other stuff here].join("\n")
|
18
|
+
File.open(user_ignore_file, 'w') do |fh|
|
19
|
+
fh.write "#{token}\n"
|
20
|
+
end
|
21
|
+
subject.stub(:user_ignore_file).and_return(user_ignore_file)
|
22
|
+
end
|
23
|
+
|
24
|
+
specify "then the file is ignored" do
|
25
|
+
File.read('~/.gitignore').should match /#{token}/
|
26
|
+
subject.ignored?(token).should be_true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ignorance/hg_ignore_file'
|
3
|
+
|
4
|
+
module Ignorance
|
5
|
+
describe HgIgnoreFile, :fakefs do
|
6
|
+
|
7
|
+
let(:ignore_file) { '.hgignore' }
|
8
|
+
let(:repo_dir) { '.hg' }
|
9
|
+
|
10
|
+
it_should_behave_like "an ignore file"
|
11
|
+
it_should_behave_like "a project-oriented VCS"
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ignorance'
|
3
|
+
|
4
|
+
describe Ignorance do
|
5
|
+
|
6
|
+
describe "class methods (e.g. Ingorance.guard...)" do
|
7
|
+
subject { Ignorance }
|
8
|
+
it { should respond_to :advise, :guard, :negotiate, :guarantee! }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "when included" do
|
12
|
+
before do
|
13
|
+
class TestIncluder
|
14
|
+
include Ignorance
|
15
|
+
end
|
16
|
+
end
|
17
|
+
subject { TestIncluder.new }
|
18
|
+
|
19
|
+
it do
|
20
|
+
should respond_to :advise_ignorance,
|
21
|
+
:guard_ignorance,
|
22
|
+
:negotiate_ignorance,
|
23
|
+
:guarantee_ignorance!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "with Git" do
|
28
|
+
let(:ignore_file) { '.gitignore' }
|
29
|
+
let(:repo_dir) { '.git' }
|
30
|
+
|
31
|
+
it_should_behave_like Ignorance
|
32
|
+
end
|
33
|
+
|
34
|
+
context "with Mercurial" do
|
35
|
+
let(:ignore_file) { '.hgignore' }
|
36
|
+
let(:repo_dir) { '.hg' }
|
37
|
+
|
38
|
+
it_should_behave_like Ignorance
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
context "with SVN" do
|
43
|
+
let(:ignore_file) { '.svnignore' }
|
44
|
+
let(:repo_dir) { '.svn' }
|
45
|
+
|
46
|
+
it_should_behave_like Ignorance
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
shared_examples Ignorance do
|
2
|
+
|
3
|
+
context "So anyway...", :fakefs do
|
4
|
+
before { mk_repo_dir }
|
5
|
+
let(:token) { "foo.rb" }
|
6
|
+
|
7
|
+
describe "::advise", :capture_io do
|
8
|
+
|
9
|
+
context "token is already in ignore file" do
|
10
|
+
before { ignorefile_write "#{token}\n" }
|
11
|
+
|
12
|
+
it "does not warn" do
|
13
|
+
expect( stderr_from { Ignorance.advise token } ).to be_empty
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "token is NOT in ignore file" do
|
18
|
+
before { ignorefile_write "something-else.txt\n" }
|
19
|
+
|
20
|
+
it "prints warn (STDERR)" do
|
21
|
+
expect( stderr_from { Ignorance.advise token } ).to match /WARNING:.*add "#{token}" to .*#{ignore_file}/
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "::guard" do
|
27
|
+
context "token is already in ignore file" do
|
28
|
+
before { ignorefile_write "#{token}\n" }
|
29
|
+
|
30
|
+
specify "no error is raised" do
|
31
|
+
expect { Ignorance.guard token }.to_not raise_error
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "token is NOT in ignore file" do
|
36
|
+
before { ignorefile_write "something-else.txt\n" }
|
37
|
+
|
38
|
+
it "raises an error" do
|
39
|
+
expect { Ignorance.guard token }.to raise_error Ignorance::IgnorefileError, /add "#{token}" to .*#{ignore_file}/
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "::negotiate", :capture_io do
|
45
|
+
|
46
|
+
context "token is already in ignore file" do
|
47
|
+
before { ignorefile_write "#{token}\n" }
|
48
|
+
|
49
|
+
it "does nothing" do
|
50
|
+
expect( stdout_from { Ignorance.negotiate token } ).to be_empty
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "token is NOT in ignore file" do
|
55
|
+
before { ignorefile_write "stuff.txt\n" }
|
56
|
+
|
57
|
+
context "user agrees (y)" do
|
58
|
+
specify do
|
59
|
+
expect( user_types("y") { Ignorance.negotiate token } ).to match /added "#{token}"/i
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "user disagrees (n)" do
|
64
|
+
specify do
|
65
|
+
expect( user_types("n") { Ignorance.negotiate token } ).to match /WARNING:.*add "#{token}" to .*#{ignore_file}/
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "::guarantee!" do
|
72
|
+
context "token is already in ignore file" do
|
73
|
+
before { ignorefile_write "#{token}\n" }
|
74
|
+
|
75
|
+
it "does not change the ignore file" do
|
76
|
+
Ignorance.guarantee! token, "a comment"
|
77
|
+
ignorefile_contents.should == "#{token}\n"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "token is NOT in ignore file" do
|
82
|
+
before { ignorefile_write "stuff.txt\n" }
|
83
|
+
|
84
|
+
it "adds to the ignore file" do
|
85
|
+
Ignorance.guarantee! token, "a comment"
|
86
|
+
ignorefile_contents.should == "stuff.txt\n\n# a comment\n#{token}\n"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module Ignorance
|
2
|
+
shared_examples "an ignore file" do
|
3
|
+
|
4
|
+
it { should respond_to :name, :exists?, :its_a_repo?, :ignored?, :ignore! }
|
5
|
+
its(:name) { should == ignore_file }
|
6
|
+
|
7
|
+
describe "#exists?" do
|
8
|
+
|
9
|
+
context "when the ignore file does NOT exist" do
|
10
|
+
it { should_not exist }
|
11
|
+
end
|
12
|
+
|
13
|
+
context "when the ignore file DOES exist" do
|
14
|
+
before { ignorefile_write "" }
|
15
|
+
it { should exist }
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
describe "#its_a_repo?" do
|
22
|
+
|
23
|
+
context "when the repo subdirectory does NOT exist" do
|
24
|
+
it { should_not be_its_a_repo }
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when the repo subdirectory DOES exist" do
|
28
|
+
before { Dir.mkdir repo_dir }
|
29
|
+
it { should be_its_a_repo }
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#ignored?" do
|
35
|
+
let(:token) { "foofile.txt" }
|
36
|
+
|
37
|
+
context "when the ignore file doesn't exist" do
|
38
|
+
specify "then the file is not ignored, duh" do
|
39
|
+
subject.should_not exist
|
40
|
+
subject.ignored?(token).should == false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when the ignore file does exist" do
|
45
|
+
|
46
|
+
context "when the ignore file doesn't include the token" do
|
47
|
+
before { ignorefile_write %w[other stuff here].join("\n") }
|
48
|
+
it { should_not be_ignored(token) }
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when the ignore file DOES include the token" do
|
52
|
+
before { ignorefile_write ["other", token+"", "stuff"].join("\n") }
|
53
|
+
it { should be_ignored(token) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
describe "#ignore!" do
|
61
|
+
let(:token) { "foofile.txt" }
|
62
|
+
|
63
|
+
context "there is no ignore file" do
|
64
|
+
it "writes to the ignore file" do
|
65
|
+
subject.should_not exist
|
66
|
+
subject.ignore! token
|
67
|
+
ignored_tokens.should include token
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "there is already an ignore file" do
|
72
|
+
before { ignorefile_write "*.swp\n" }
|
73
|
+
specify do
|
74
|
+
ignored_tokens.should include '*.swp'
|
75
|
+
subject.ignore! token
|
76
|
+
ignored_tokens.should include '*.swp'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "the token is already in the ignore file" do
|
81
|
+
let(:content) { "other\n#{token}\nstuff\n" }
|
82
|
+
before { ignorefile_write content }
|
83
|
+
|
84
|
+
it "doesn't write to the ignore file" do
|
85
|
+
File.any_instance.should_not_receive(:write)
|
86
|
+
subject.ignore!(token)
|
87
|
+
ignored_tokens.should include token
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "with a comment" do
|
92
|
+
context "when the comment wasn't already in the file" do
|
93
|
+
specify do
|
94
|
+
subject.ignore! token, "# hide these files!"
|
95
|
+
ignorefile_contents.should match /# hide these files!\n#{token}\n/
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "when the comment was already in the file" do
|
100
|
+
let(:comment) { "hide these files!" }
|
101
|
+
|
102
|
+
context "comment is the last line of the file" do
|
103
|
+
before { ignorefile_write "\n# #{comment}\n" }
|
104
|
+
|
105
|
+
specify do
|
106
|
+
subject.ignore! token, comment
|
107
|
+
ignorefile_contents.should match /# #{comment}\n#{token}\n/
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context "when the comment has other tokens after it" do
|
112
|
+
before do
|
113
|
+
ignorefile_write <<-IGNORE
|
114
|
+
# #{comment}
|
115
|
+
barfile.md
|
116
|
+
|
117
|
+
other-things
|
118
|
+
IGNORE
|
119
|
+
end
|
120
|
+
let(:expected) { Regexp.new /# #{comment}\nbarfile\.md\n#{token}\n\nother-things/ }
|
121
|
+
|
122
|
+
specify do
|
123
|
+
subject.ignore! token, comment
|
124
|
+
ignorefile_contents.should match expected
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "when comment has other tokens at end of file" do
|
129
|
+
before do
|
130
|
+
ignorefile_write <<-IGNORE
|
131
|
+
# #{comment}
|
132
|
+
barfile.md
|
133
|
+
IGNORE
|
134
|
+
end
|
135
|
+
let(:expected) { Regexp.new /# #{comment}\nbarfile\.md\n#{token}\n/ }
|
136
|
+
|
137
|
+
specify do
|
138
|
+
subject.ignore! token, comment
|
139
|
+
ignorefile_contents.should match expected
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
shared_examples "a project-oriented VCS" do
|
2
|
+
|
3
|
+
describe "#its_a_repo?", :fakefs do
|
4
|
+
context "pwd is a subdirectory of the repo root" do
|
5
|
+
before do
|
6
|
+
mk_repo_dir
|
7
|
+
Dir.mkdir 'lib'
|
8
|
+
Dir.mkdir 'lib/other'
|
9
|
+
Dir.chdir 'lib/other'
|
10
|
+
end
|
11
|
+
|
12
|
+
it { should be_its_a_repo }
|
13
|
+
end
|
14
|
+
|
15
|
+
context "pwd is not the subdirectory of any repo" do
|
16
|
+
before do
|
17
|
+
Dir.mkdir 'lib'
|
18
|
+
Dir.mkdir 'lib/other'
|
19
|
+
Dir.chdir 'lib/other'
|
20
|
+
end
|
21
|
+
|
22
|
+
it { should_not be_its_a_repo }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'fakefs/spec_helpers'
|
2
|
+
require File.join(File.dirname(__FILE__), 'ignorefile_helpers')
|
3
|
+
require File.join(File.dirname(__FILE__), 'io_helpers')
|
4
|
+
|
5
|
+
here = File.dirname(__FILE__)
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift(File.expand_path(File.join(here, '..', '..', 'lib')))
|
8
|
+
|
9
|
+
Dir[File.join(here, "shared_examples") + "/**/*.rb"].sort.map{|f| File.basename f }.map{|f| "shared_examples/#{f}"}.each {|f| require f}
|
10
|
+
|
11
|
+
RSpec.configure do |cfg|
|
12
|
+
cfg.treat_symbols_as_metadata_keys_with_true_values = true
|
13
|
+
cfg.include FakeFS::SpecHelpers, fakefs: true
|
14
|
+
cfg.include IgnorefileHelpers, fakefs: true
|
15
|
+
cfg.include IOHelpers, capture_io: true
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ignorance
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joel Helbling
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: highline
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.6.15
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.6.15
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 2.12.0
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.12.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: fakefs
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.4.2
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.4.2
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: pry
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 0.9.11.4
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 0.9.11.4
|
78
|
+
description: Ensures specified files are ignored by Git, Mercurial or SVN.
|
79
|
+
email:
|
80
|
+
- joel@joelhelbling.com
|
81
|
+
executables: []
|
82
|
+
extensions: []
|
83
|
+
extra_rdoc_files: []
|
84
|
+
files:
|
85
|
+
- .gitignore
|
86
|
+
- Gemfile
|
87
|
+
- LICENSE.txt
|
88
|
+
- README.md
|
89
|
+
- Rakefile
|
90
|
+
- ignorance.gemspec
|
91
|
+
- lib/ignorance.rb
|
92
|
+
- lib/ignorance/git_ignore_file.rb
|
93
|
+
- lib/ignorance/hg_ignore_file.rb
|
94
|
+
- lib/ignorance/ignore_file.rb
|
95
|
+
- lib/ignorance/project_oriented_vcs.rb
|
96
|
+
- lib/ignorance/svn_ignore_file.rb
|
97
|
+
- lib/ignorance/version.rb
|
98
|
+
- spec/ignorefile_helpers.rb
|
99
|
+
- spec/io_helpers.rb
|
100
|
+
- spec/lib/ignorance/git_ignore_file_spec.rb
|
101
|
+
- spec/lib/ignorance/hg_ignore_file_spec.rb
|
102
|
+
- spec/lib/ignorance/ignore_file_spec.rb
|
103
|
+
- spec/lib/ignorance/svn_ignore_file_spec.rb
|
104
|
+
- spec/lib/ignorance_spec.rb
|
105
|
+
- spec/shared_examples/for_ignorance.rb
|
106
|
+
- spec/shared_examples/for_ignore_files.rb
|
107
|
+
- spec/shared_examples/for_project_oriented_vcs.rb
|
108
|
+
- spec/spec_helper.rb
|
109
|
+
homepage: http://github.com/joelhelbling/ignorance
|
110
|
+
licenses: []
|
111
|
+
post_install_message:
|
112
|
+
rdoc_options: []
|
113
|
+
require_paths:
|
114
|
+
- lib
|
115
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ! '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
requirements: []
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 1.8.24
|
130
|
+
signing_key:
|
131
|
+
specification_version: 3
|
132
|
+
summary: Ignorance helps your code be considerate of its users by protecting sensitive
|
133
|
+
information from version control.
|
134
|
+
test_files:
|
135
|
+
- spec/ignorefile_helpers.rb
|
136
|
+
- spec/io_helpers.rb
|
137
|
+
- spec/lib/ignorance/git_ignore_file_spec.rb
|
138
|
+
- spec/lib/ignorance/hg_ignore_file_spec.rb
|
139
|
+
- spec/lib/ignorance/ignore_file_spec.rb
|
140
|
+
- spec/lib/ignorance/svn_ignore_file_spec.rb
|
141
|
+
- spec/lib/ignorance_spec.rb
|
142
|
+
- spec/shared_examples/for_ignorance.rb
|
143
|
+
- spec/shared_examples/for_ignore_files.rb
|
144
|
+
- spec/shared_examples/for_project_oriented_vcs.rb
|
145
|
+
- spec/spec_helper.rb
|