gitattributes 1.1.0 → 2.0.0

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
2
  SHA1:
3
- metadata.gz: 7ce63e4149e74cf32bbff64049cf633fac63ba63
4
- data.tar.gz: 2cb92c1110a46176e0e4e973fd8a0c2c02087186
3
+ metadata.gz: 4055ed6765e1558b96eebb9b052de3fbfc27eff3
4
+ data.tar.gz: 34f605af19c5218246de1dcab55ddbb438217c62
5
5
  SHA512:
6
- metadata.gz: e70fd5e6e915580d2aa0358556ba0e7dd338a2cf451557cc163df5cad9637098be78316c6cd93c0cb1e58e59831e51eafad699be992f34da702fb996f4f6cb37
7
- data.tar.gz: 446c351faf8abda62986acb0ea4e2e7b742605baeeab662e04052f2e5509a97ee670683cabc805ea4e0d6144388f2712fd9a8584216e6214469140a9a86c71be
6
+ metadata.gz: cd290ced985cf1e8f854faffea25d7ed27d7ae260ccca267a43393090e55163590ac167b29d487c4a271bee9cd6c4fce6b6809fe96997219e91e682944bd7bdb
7
+ data.tar.gz: 65d810237cea85dcb80c1ea0a2be88cd3137e07e59bce344a1aab6956cd7abde8a3e288e2245e747fca6d0e3b9086d04e247c0a69412382aacca65f2006bce92
data/LICENSE CHANGED
@@ -1,20 +1,202 @@
1
- Copyright (c) 2017 Peter Donald
2
- Copyright (c) 2013 Dmitriy Zaporozhets
3
-
4
- Permission is hereby granted, free of charge, to any person obtaining a copy
5
- of this software and associated documentation files (the "Software"), to deal
6
- in the Software without restriction, including without limitation the rights
7
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- copies of the Software, and to permit persons to whom the Software is
9
- furnished to do so, subject to the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be included in
12
- all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
- THE SOFTWARE.
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
data/README.md CHANGED
@@ -7,12 +7,6 @@ Classes to parse `.gitattributes` files.
7
7
  A simple example of it's usage:
8
8
 
9
9
  ```ruby
10
- attributes = Reality::GitAttributes.new('/home/user/myrepo')
10
+ attributes = Reality::Git::Attributes.parse('/home/user/myrepo')
11
11
  attributes.attributes('README.md') # => { "eol" => "lf }
12
12
  ```
13
-
14
- ## Credit
15
-
16
- These classes were extracted from the [gitlab_git](https://gitlab.com/ben.boeckel/gitlab_git) by
17
- with the gitattribtues code originally authored by Douwe Maan. All credit goes to the original
18
- authors.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{gitattributes}
5
- s.version = '1.1.0'
5
+ s.version = '2.0.0'
6
6
  s.platform = Gem::Platform::RUBY
7
7
 
8
8
  s.authors = ['Peter Donald']
@@ -0,0 +1,85 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ module Reality #nodoc
16
+ module Git
17
+ # Represents a rule within the attributes file
18
+ class AttributeRule
19
+ ATTR_ORDER = %w(text crlf binary eofnl)
20
+
21
+ def initialize(pattern, attributes)
22
+ @pattern = pattern
23
+ @attributes = {}
24
+ @priority = 1
25
+ attributes.each do |k, v|
26
+ if k.to_s == 'priority'
27
+ @priority = v
28
+ else
29
+ @attributes[k.to_s] = v
30
+ end
31
+ end
32
+ end
33
+
34
+ attr_reader :pattern
35
+ attr_reader :attributes
36
+ attr_reader :priority
37
+
38
+ def to_s
39
+ rule = self.pattern
40
+
41
+ attributes = self.attributes.dup
42
+ ATTR_ORDER.each do |key|
43
+ unless attributes[key].nil?
44
+ rule = "#{rule}#{attr_value(key, attributes[key])}"
45
+ end
46
+ end
47
+ attributes.keys.sort.each do |key|
48
+ unless ATTR_ORDER.include?(key)
49
+ rule = "#{rule}#{attr_value(key, attributes[key])}"
50
+ end
51
+ end
52
+
53
+ rule
54
+ end
55
+
56
+ # noinspection RubySimplifyBooleanInspection
57
+ def attr_value(key, value)
58
+ if true == value
59
+ " #{key}"
60
+ elsif false == value
61
+ " -#{key}"
62
+ else
63
+ " #{key}=#{value}"
64
+ end
65
+ end
66
+
67
+ def eql?(other)
68
+ self.pattern == other.pattern && self.attributes == other.attributes && self.priority == other.priority
69
+ end
70
+
71
+ def hash
72
+ self.pattern.hash + self.attributes.hash + self.priority
73
+ end
74
+
75
+ def <=>(other)
76
+ order = self.priority <=> other.priority
77
+ if 0 != order
78
+ order
79
+ else
80
+ to_s <=> other.to_s
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,83 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ module Reality #nodoc
16
+ module Git #nodoc
17
+ # Representation of a gitattributes file.
18
+ class Attributes
19
+
20
+ class << self
21
+ # path - The path to the Git repository.
22
+ # attributes_file - The path to the ".gitattributes" file. Defaults to "<path>/.gitattributes".
23
+ # relative_path - The path to which attributes apply. Defaults to direcotyr containing attributes file.
24
+ def parse(repository_path, attributes_file = nil, relative_path = nil)
25
+ path = File.expand_path(repository_path)
26
+ attributes_file ||= "#{path}/.gitattributes"
27
+ rules = File.exist?(attributes_file) ? Reality::Git::AttributesParser.parse_file(attributes_file) : {}
28
+ Attributes.new(repository_path, attributes_file, relative_path, rules)
29
+ end
30
+ end
31
+
32
+ def initialize(repository_path, attributes_file = nil, relative_path = nil, rules = [])
33
+ @path = File.expand_path(repository_path)
34
+ @attributes_file = attributes_file || "#{@path}/.gitattributes"
35
+ @relative_path = relative_path || File.dirname(@attributes_file)
36
+ @rules = rules
37
+ end
38
+
39
+ attr_reader :attributes_file
40
+
41
+ # Returns the attributes for the specified path as a hash.
42
+ def attributes(path)
43
+ full_path = File.join(@path, path)
44
+
45
+ @rules.reverse.each do |rule|
46
+ return rule.attributes if File.fnmatch?(File.join(@relative_path, rule.pattern), full_path)
47
+ end
48
+
49
+ {}
50
+ end
51
+
52
+ def write_to(filename, options = {})
53
+ prefix = options[:prefix].nil? ? '' : "#{options[:prefix]}\n"
54
+ rules = options[:normalize] ? @rules.dup.sort.uniq : @rules
55
+ content = rules.collect {|r| r.to_s}.join("\n")
56
+ content += "\n" unless content.empty?
57
+ IO.write(filename, prefix + content)
58
+ end
59
+
60
+ def rule(pattern, attributes)
61
+ @rules << AttributeRule.new(pattern, attributes)
62
+ end
63
+
64
+ def text_rule(pattern, attributes = {})
65
+ rule(pattern, { :text => true, :crlf => false, :binary => false }.merge(attributes))
66
+ end
67
+
68
+ def dos_text_rule(pattern, attributes = {})
69
+ text_rule(pattern, { :crlf => true }.merge(attributes))
70
+ end
71
+
72
+ def binary_rule(pattern, attributes = {})
73
+ rule(pattern, { :binary => true }.merge(attributes))
74
+ end
75
+
76
+ # Returns a list of attribute rules to apply.
77
+ def rules
78
+ @rules.dup
79
+ end
80
+ end
81
+ end
82
+ end
83
+
@@ -0,0 +1,104 @@
1
+ # Copyright (c) 2017 Peter Donald
2
+ # Copyright (c) 2013 Dmitriy Zaporozhets
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ # These classes were extracted from the https://gitlab.com/ben.boeckel/gitlab_git repository
23
+ # with the gitattribtues code originally authored by Douwe Maan. Credit to the original authors.
24
+
25
+ module Reality #nodoc
26
+ module Git
27
+ # Parse the Git attribute file extracting the attributes for file patterns.
28
+ module AttributesParser
29
+ class << self
30
+
31
+ # Parses the specified Git attributes file.
32
+ def parse_file(filename)
33
+ rules = []
34
+ comment = '#'
35
+
36
+ IO.readlines(filename).each do |line|
37
+ next if line.start_with?(comment) || line.empty?
38
+
39
+ pattern, attrs = line.split(/\s+/, 2)
40
+
41
+ parsed_attributes = attrs ? parse_attributes(attrs) : {}
42
+
43
+ rules << AttributeRule.new(pattern, parsed_attributes)
44
+ end
45
+
46
+ # Newer entries take precedence over older entries.
47
+ rules
48
+ end
49
+
50
+ private
51
+
52
+ # Parses an attribute string.
53
+ #
54
+ # These strings can be in the following formats:
55
+ #
56
+ # text # => { "text" => true }
57
+ # -text # => { "text" => false }
58
+ # key=value # => { "key" => "value" }
59
+ #
60
+ # string - The string to parse.
61
+ #
62
+ # Returns a Hash containing the attributes and their values.
63
+ def parse_attributes(string)
64
+ values = {}
65
+ dash = '-'
66
+ equal = '='
67
+ binary = 'binary'
68
+
69
+ string.split(/\s+/).each do |chunk|
70
+ # Data such as "foo = bar" should be treated as "foo" and "bar" being
71
+ # separate boolean attributes.
72
+ next if chunk == equal
73
+
74
+ key = chunk
75
+
76
+ # Input: "-foo"
77
+ if chunk.start_with?(dash)
78
+ key = chunk.byteslice(1, chunk.length - 1)
79
+ value = false
80
+
81
+ # Input: "foo=bar"
82
+ elsif chunk.include?(equal)
83
+ key, value = chunk.split(equal, 2)
84
+
85
+ # Input: "foo"
86
+ else
87
+ value = true
88
+ end
89
+
90
+ values[key] = value
91
+
92
+ # When the "binary" option is set the "diff" option should be set to
93
+ # the inverse. If "diff" is later set it should overwrite the
94
+ # automatically set value.
95
+ values['diff'] = false if key == binary && value
96
+ end
97
+
98
+ values
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+
@@ -1,123 +1,17 @@
1
- module Reality
2
- # Class for parsing Git attribute files and extracting the attributes for
3
- # file patterns.
4
- #
5
- # Basic usage:
6
- #
7
- # attributes = Reality::Git::Attributes.new(some_repo.path)
8
- #
9
- # attributes.attributes('README.md') # => { "eol" => "lf }
10
- class GitAttributes
11
- # path - The path to the Git repository.
12
- # attributes_file - The path to the ".gitattribtues" file. Defaults to "<path>/.gitattribtues".
13
- def initialize(repository_path, attributes_file = nil)
14
- @path = File.expand_path(repository_path)
15
- @attributes_file = attributes_file || "#{@path}/.gitattributes"
16
- @patterns = nil
17
- end
18
-
19
- # Returns all the Git attributes for the given path.
20
- #
21
- # path - A path to a file for which to get the attributes.
22
- #
23
- # Returns a Hash.
24
- def attributes(path)
25
- full_path = File.join(@path, path)
26
-
27
- patterns.each do |pattern, attrs|
28
- return attrs if File.fnmatch?(pattern, full_path)
29
- end
30
-
31
- {}
32
- end
33
-
34
- # Returns a Hash containing the file patterns and their attributes.
35
- def patterns
36
- @patterns ||= parse_file
37
- end
38
-
39
- private
40
-
41
- # Parses an attribute string.
42
- #
43
- # These strings can be in the following formats:
44
- #
45
- # text # => { "text" => true }
46
- # -text # => { "text" => false }
47
- # key=value # => { "key" => "value" }
48
- #
49
- # string - The string to parse.
50
- #
51
- # Returns a Hash containing the attributes and their values.
52
- def parse_attributes(string)
53
- values = {}
54
- dash = '-'
55
- equal = '='
56
- binary = 'binary'
57
-
58
- string.split(/\s+/).each do |chunk|
59
- # Data such as "foo = bar" should be treated as "foo" and "bar" being
60
- # separate boolean attributes.
61
- next if chunk == equal
62
-
63
- key = chunk
64
-
65
- # Input: "-foo"
66
- if chunk.start_with?(dash)
67
- key = chunk.byteslice(1, chunk.length - 1)
68
- value = false
69
-
70
- # Input: "foo=bar"
71
- elsif chunk.include?(equal)
72
- key, value = chunk.split(equal, 2)
73
-
74
- # Input: "foo"
75
- else
76
- value = true
77
- end
78
-
79
- values[key] = value
80
-
81
- # When the "binary" option is set the "diff" option should be set to
82
- # the inverse. If "diff" is later set it should overwrite the
83
- # automatically set value.
84
- values['diff'] = false if key == binary && value
85
- end
86
-
87
- values
88
- end
89
-
90
- # Iterates over every line in the attributes file.
91
- def each_line
92
- full_path = @attributes_file
93
-
94
- return unless File.exist?(full_path)
95
-
96
- File.open(full_path, 'r') do |handle|
97
- handle.each_line do |line|
98
- yield line.strip
99
- end
100
- end
101
- end
102
-
103
- # Parses the Git attributes file.
104
- def parse_file
105
- pairs = []
106
- comment = '#'
107
-
108
- each_line do |line|
109
- next if line.start_with?(comment) || line.empty?
110
-
111
- pattern, attrs = line.split(/\s+/, 2)
112
-
113
- parsed = attrs ? parse_attributes(attrs) : {}
114
-
115
- pairs << [File.join(@path, pattern), parsed]
116
- end
117
-
118
- # Newer entries take precedence over older entries.
119
- pairs.reverse.to_h
120
- end
121
- end
122
- end
123
-
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ require 'reality/git/attribute_rule'
16
+ require 'reality/git/attributes_parser'
17
+ require 'reality/git/attributes'
@@ -0,0 +1,59 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ require File.expand_path('../../../helper', __FILE__)
16
+
17
+ class Reality::Git::TestAttributeRule < Reality::TestCase
18
+ def test_basic_operation
19
+ rule = Reality::Git::AttributeRule.new('*', 'text' => false)
20
+ assert_equal({ 'text' => false }, rule.attributes)
21
+ assert_equal('* -text', rule.to_s)
22
+ assert_equal(1, rule.priority)
23
+ end
24
+
25
+ def test_priority_specified
26
+ rule = Reality::Git::AttributeRule.new('*', 'text' => false, 'priority' => 3)
27
+ assert_equal(3, rule.priority)
28
+ assert_equal({ 'text' => false }, rule.attributes)
29
+ assert_equal('* -text', rule.to_s)
30
+ end
31
+
32
+ def test_many_attributes
33
+ rule = Reality::Git::AttributeRule.new('*.rdl', 'eofnl' => false, 'text' => true, 'crlf' => true, 'binary' => false, 'ms-file' => 'RPT', 'age' => '22')
34
+ assert_equal({ 'eofnl' => false, 'text' => true, 'crlf' => true, 'binary' => false, 'ms-file' => 'RPT', 'age' => '22' }, rule.attributes)
35
+ assert_equal('*.rdl text crlf -binary -eofnl age=22 ms-file=RPT', rule.to_s)
36
+ end
37
+
38
+ def test_sorting
39
+ rule1 = Reality::Git::AttributeRule.new('*.a', 'priority' => 2, 'text' => true)
40
+ rule2 = Reality::Git::AttributeRule.new('*.b', 'priority' => 2, 'text' => true)
41
+ rule3 = Reality::Git::AttributeRule.new('*.c', 'priority' => 1, 'text' => true)
42
+ assert_equal(0, rule1 <=> rule1)
43
+ assert_equal(0, rule2 <=> rule2)
44
+ assert_equal(0, rule3 <=> rule3)
45
+ assert_equal(-1, rule1 <=> rule2)
46
+ assert_equal(1, rule1 <=> rule3)
47
+ assert_equal(1, rule2 <=> rule3)
48
+ assert_equal([rule3, rule1, rule2], [rule1, rule2, rule3].sort)
49
+ end
50
+
51
+ def test_eql
52
+ rule1 = Reality::Git::AttributeRule.new('*.a', 'priority' => 2, 'text' => true)
53
+ rule2 = Reality::Git::AttributeRule.new('*.a', 'priority' => 3, 'text' => true)
54
+ assert_equal(true, rule1.eql?(rule1))
55
+ assert_equal(rule1.hash, rule1.hash)
56
+ assert_equal(false, rule1.eql?(rule2))
57
+ assert_not_equal(rule1.hash, rule2.hash)
58
+ end
59
+ end
@@ -0,0 +1,281 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ require File.expand_path('../../../helper', __FILE__)
16
+
17
+ class Reality::TestAttributes < Reality::TestCase
18
+ def test_basic_operation_using_default_attributes
19
+ content = <<TEXT
20
+ * -text
21
+ TEXT
22
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
23
+ write_standard_file(dir, content)
24
+
25
+ attributes = Reality::Git::Attributes.parse(dir)
26
+ assert_equal("#{dir}/.gitattributes", attributes.attributes_file)
27
+ assert_equal(['* -text'], attributes.rules.collect {|p| p.to_s})
28
+
29
+ assert_equal({ 'text' => false }, attributes.attributes('README.md'))
30
+ end
31
+
32
+ def test_gitattributes_in_non_standard_location
33
+ content = <<TEXT
34
+ * -text
35
+ TEXT
36
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
37
+ attributes_file = "#{dir}/non-standard-gitattributes"
38
+ write_file(attributes_file, content)
39
+
40
+ attributes = Reality::Git::Attributes.parse(dir, attributes_file)
41
+ assert_equal(attributes_file, attributes.attributes_file)
42
+ assert_equal(['* -text'], attributes.rules.collect {|p| p.to_s})
43
+
44
+ assert_equal({ 'text' => false }, attributes.attributes('README.md'))
45
+ assert_equal({ 'text' => false }, attributes.attributes('docs/README.md'))
46
+ end
47
+
48
+ def test_multi_value_attribute
49
+ content = <<TEXT
50
+ *.textile text -crlf -binary
51
+ TEXT
52
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
53
+ write_standard_file(dir, content)
54
+
55
+ attributes = Reality::Git::Attributes.parse(dir)
56
+ assert_equal(['*.textile text -crlf -binary'], attributes.rules.collect {|p| p.to_s})
57
+
58
+ assert_equal({}, attributes.attributes('README.md'))
59
+ assert_equal({ 'text' => true, 'crlf' => false, 'binary' => false }, attributes.attributes('README.textile'))
60
+ assert_equal({ 'text' => true, 'crlf' => false, 'binary' => false }, attributes.attributes('doc/X.textile'))
61
+ end
62
+
63
+ def test_multi_patterns
64
+ content = <<TEXT
65
+ * -text
66
+ *.textile text -crlf -binary
67
+ TEXT
68
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
69
+ write_standard_file(dir, content)
70
+
71
+ attributes = Reality::Git::Attributes.parse(dir)
72
+ assert_equal(['* -text', '*.textile text -crlf -binary'], attributes.rules.collect {|p| p.to_s})
73
+
74
+ assert_equal({ 'text' => false }, attributes.attributes('README.md'))
75
+ assert_equal({ 'text' => true, 'crlf' => false, 'binary' => false }, attributes.attributes('doc/X.textile'))
76
+ end
77
+
78
+ def test_ignore_comments
79
+ content = <<TEXT
80
+ # DO NOT EDIT: File is auto-generated
81
+ * -text
82
+ # DO NOT EDIT: File is auto-generated
83
+ TEXT
84
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
85
+ write_standard_file(dir, content)
86
+
87
+ attributes = Reality::Git::Attributes.parse(dir)
88
+ assert_equal("#{dir}/.gitattributes", attributes.attributes_file)
89
+ assert_equal(['* -text'], attributes.rules.collect {|p| p.to_s})
90
+ end
91
+
92
+ def test_relative_dir
93
+ content = <<TEXT
94
+ doc/*.md text
95
+ TEXT
96
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
97
+ write_standard_file(dir, content)
98
+
99
+ attributes = Reality::Git::Attributes.parse(dir)
100
+ assert_equal("#{dir}/.gitattributes", attributes.attributes_file)
101
+ assert_equal(['doc/*.md text'], attributes.rules.collect {|p| p.to_s})
102
+
103
+ assert_equal({}, attributes.attributes('README.md'))
104
+ assert_equal({ 'text' => true }, attributes.attributes('doc/X.md'))
105
+ end
106
+
107
+ def test_gitattributes_in_subdirectory
108
+ content = <<TEXT
109
+ * -text
110
+ TEXT
111
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
112
+ attributes_file = "#{dir}/foo/.gitattributes"
113
+ write_file(attributes_file, content)
114
+
115
+ attributes = Reality::Git::Attributes.parse(dir, attributes_file)
116
+ assert_equal(attributes_file, attributes.attributes_file)
117
+ assert_equal(['* -text'], attributes.rules.collect {|p| p.to_s})
118
+
119
+ assert_equal({}, attributes.attributes('README.md'))
120
+ assert_equal({ 'text' => false }, attributes.attributes('foo/docs/README.md'))
121
+ end
122
+
123
+ def test_write_to
124
+ content = <<TEXT
125
+ * -text
126
+ TEXT
127
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
128
+ write_standard_file(dir, content)
129
+
130
+ attributes = Reality::Git::Attributes.parse(dir)
131
+ assert_equal("#{dir}/.gitattributes", attributes.attributes_file)
132
+ assert_equal(['* -text'], attributes.rules.collect {|p| p.to_s})
133
+
134
+ output_filename = "#{dir}/output_gitattributes"
135
+ attributes.write_to(output_filename)
136
+
137
+ assert_equal(<<TEXT, IO.read(output_filename))
138
+ * -text
139
+ TEXT
140
+ end
141
+
142
+ def test_write_to_with_multiple_rules
143
+ content = <<TEXT
144
+ *.md text
145
+ * -text
146
+ *.java text
147
+ TEXT
148
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
149
+ write_standard_file(dir, content)
150
+
151
+ attributes = Reality::Git::Attributes.parse(dir)
152
+ assert_equal("#{dir}/.gitattributes", attributes.attributes_file)
153
+ assert_equal(['*.md text', '* -text', '*.java text'], attributes.rules.collect {|p| p.to_s})
154
+
155
+ output_filename = "#{dir}/output_gitattributes"
156
+ attributes.write_to(output_filename)
157
+
158
+ assert_equal(<<TEXT, IO.read(output_filename))
159
+ *.md text
160
+ * -text
161
+ *.java text
162
+ TEXT
163
+ end
164
+
165
+ def test_write_to_with_normalization
166
+ content = <<TEXT
167
+ *.md text
168
+ * -text
169
+ *.java text
170
+ *.java text
171
+ TEXT
172
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
173
+ write_standard_file(dir, content)
174
+
175
+ attributes = Reality::Git::Attributes.parse(dir)
176
+ assert_equal("#{dir}/.gitattributes", attributes.attributes_file)
177
+ assert_equal(['*.md text', '* -text', '*.java text', '*.java text'], attributes.rules.collect {|p| p.to_s})
178
+
179
+ output_filename = "#{dir}/output_gitattributes"
180
+ attributes.write_to(output_filename, :normalize => true)
181
+
182
+ assert_equal(<<TEXT, IO.read(output_filename))
183
+ * -text
184
+ *.java text
185
+ *.md text
186
+ TEXT
187
+ end
188
+
189
+ def test_write_to_with_prefix
190
+ content = <<TEXT
191
+ * -text
192
+ TEXT
193
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
194
+ write_standard_file(dir, content)
195
+
196
+ attributes = Reality::Git::Attributes.parse(dir)
197
+ assert_equal("#{dir}/.gitattributes", attributes.attributes_file)
198
+ assert_equal(['* -text'], attributes.rules.collect {|p| p.to_s})
199
+
200
+ output_filename = "#{dir}/output_gitattributes"
201
+ attributes.write_to(output_filename, :prefix => '# DO NOT EDIT: File is auto-generated')
202
+
203
+ assert_equal(<<TEXT, IO.read(output_filename))
204
+ # DO NOT EDIT: File is auto-generated
205
+ * -text
206
+ TEXT
207
+ end
208
+
209
+ def test_add_rule
210
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
211
+
212
+ attributes = Reality::Git::Attributes.new(dir)
213
+
214
+ assert_equal([], attributes.rules.collect {|p| p.to_s})
215
+
216
+ attributes.rule('*', :text => false)
217
+
218
+ assert_equal(['* -text'], attributes.rules.collect {|p| p.to_s})
219
+ end
220
+
221
+ def test_add_multiple_rules
222
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
223
+
224
+ attributes = Reality::Git::Attributes.new(dir)
225
+
226
+ assert_equal([], attributes.rules.collect {|p| p.to_s})
227
+
228
+ attributes.rule('*', :text => false)
229
+ attributes.rule('*.so', :text => false)
230
+
231
+ assert_equal(['* -text', '*.so -text'], attributes.rules.collect {|p| p.to_s})
232
+ end
233
+
234
+ def test_add_text_rule
235
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
236
+
237
+ attributes = Reality::Git::Attributes.new(dir)
238
+
239
+ assert_equal([], attributes.rules.collect {|p| p.to_s})
240
+
241
+ attributes.text_rule('*.md')
242
+ attributes.text_rule('*.rake', :eofnl => false)
243
+
244
+ assert_equal(['*.md text -crlf -binary', '*.rake text -crlf -binary -eofnl'], attributes.rules.collect {|p| p.to_s})
245
+ end
246
+
247
+ def test_add_dos_text_rule
248
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
249
+
250
+ attributes = Reality::Git::Attributes.new(dir)
251
+
252
+ assert_equal([], attributes.rules.collect {|p| p.to_s})
253
+
254
+ attributes.dos_text_rule('*.cmd')
255
+ attributes.dos_text_rule('*.rdl', :eofnl => false)
256
+
257
+ assert_equal(['*.cmd text crlf -binary', '*.rdl text crlf -binary -eofnl'], attributes.rules.collect {|p| p.to_s})
258
+ end
259
+
260
+ def test_add_binary_rule
261
+ dir = "#{working_dir}/#{::SecureRandom.hex}"
262
+
263
+ attributes = Reality::Git::Attributes.new(dir)
264
+
265
+ assert_equal([], attributes.rules.collect {|p| p.to_s})
266
+
267
+ attributes.binary_rule('*.jpg')
268
+ attributes.binary_rule('*.jpg', :category => 3)
269
+
270
+ assert_equal(['*.jpg binary', '*.jpg binary category=3'], attributes.rules.collect {|p| p.to_s})
271
+ end
272
+
273
+ def write_standard_file(dir, content)
274
+ write_file("#{dir}/.gitattributes", content)
275
+ end
276
+
277
+ def write_file(attributes_file, content)
278
+ FileUtils.mkdir_p File.dirname(attributes_file)
279
+ IO.write(attributes_file, content)
280
+ end
281
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitattributes
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Donald
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-28 00:00:00.000000000 Z
11
+ date: 2017-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -54,9 +54,13 @@ files:
54
54
  - README.md
55
55
  - Rakefile
56
56
  - gitattributes.gemspec
57
+ - lib/reality/git/attribute_rule.rb
58
+ - lib/reality/git/attributes.rb
59
+ - lib/reality/git/attributes_parser.rb
57
60
  - lib/reality/gitattributes.rb
58
61
  - test/helper.rb
59
- - test/reality/test_gitattributes.rb
62
+ - test/reality/git/test_attribute_rule.rb
63
+ - test/reality/git/test_attributes.rb
60
64
  homepage: https://github.com/realityforge/gitattributes
61
65
  licenses: []
62
66
  metadata: {}
@@ -1,102 +0,0 @@
1
- #
2
- # Licensed under the Apache License, Version 2.0 (the "License");
3
- # you may not use this file except in compliance with the License.
4
- # You may obtain a copy of the License at
5
- #
6
- # http://www.apache.org/licenses/LICENSE-2.0
7
- #
8
- # Unless required by applicable law or agreed to in writing, software
9
- # distributed under the License is distributed on an "AS IS" BASIS,
10
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
- # See the License for the specific language governing permissions and
12
- # limitations under the License.
13
- #
14
-
15
- require File.expand_path('../../helper', __FILE__)
16
-
17
- class Reality::TestGitAttributes < Reality::TestCase
18
- def test_basic_operation_using_default_attribtues
19
- content = <<TEXT
20
- * -text
21
- TEXT
22
- dir = working_dir
23
- write_standard_file(dir, content)
24
-
25
- attributes = Reality::GitAttributes.new(dir)
26
- assert_equal({ "#{dir}/*" => { 'text' => false } }, attributes.patterns)
27
-
28
- assert_equal({ 'text' => false }, attributes.attributes('README.md'))
29
- end
30
-
31
- def test_gitattributes_in_non_standard_location
32
- content = <<TEXT
33
- * -text
34
- TEXT
35
- dir = working_dir
36
- attributes_file = "#{dir}/non-standard-gitattributes"
37
- write_file(attributes_file, content)
38
-
39
- attributes = Reality::GitAttributes.new(dir, attributes_file)
40
- assert_equal({ "#{dir}/*" => { 'text' => false } }, attributes.patterns)
41
-
42
- assert_equal({ 'text' => false }, attributes.attributes('README.md'))
43
- assert_equal({ 'text' => false }, attributes.attributes('docs/README.md'))
44
- end
45
-
46
- def test_multi_value_attribute
47
- content = <<TEXT
48
- *.textile text -crlf -binary
49
- TEXT
50
- dir = working_dir
51
- write_standard_file(dir, content)
52
-
53
- attributes = Reality::GitAttributes.new(dir)
54
- assert_equal({ "#{dir}/*.textile" => { 'text' => true, 'crlf' => false, 'binary' => false } },
55
- attributes.patterns)
56
-
57
- assert_equal({}, attributes.attributes('README.md'))
58
- assert_equal({ 'text' => true, 'crlf' => false, 'binary' => false }, attributes.attributes('README.textile'))
59
- assert_equal({ 'text' => true, 'crlf' => false, 'binary' => false }, attributes.attributes('doc/X.textile'))
60
- end
61
-
62
- def test_multi_patterns
63
- content = <<TEXT
64
- * -text
65
- *.textile text -crlf -binary
66
- TEXT
67
- dir = working_dir
68
- write_standard_file(dir, content)
69
-
70
- attributes = Reality::GitAttributes.new(dir)
71
- assert_equal({
72
- "#{dir}/*" => { 'text' => false },
73
- "#{dir}/*.textile" => { 'text' => true, 'crlf' => false, 'binary' => false }
74
- },
75
- attributes.patterns)
76
-
77
- assert_equal({ 'text' => false }, attributes.attributes('README.md'))
78
- assert_equal({ 'text' => true, 'crlf' => false, 'binary' => false }, attributes.attributes('doc/X.textile'))
79
- end
80
-
81
- def test_ignore_comments
82
- content = <<TEXT
83
- # DO NOT EDIT: File is auto-generated
84
- * -text
85
- # DO NOT EDIT: File is auto-generated
86
- TEXT
87
- dir = working_dir
88
- write_standard_file(dir, content)
89
-
90
- attributes = Reality::GitAttributes.new(dir)
91
- assert_equal({ "#{dir}/*" => { 'text' => false } }, attributes.patterns)
92
- end
93
-
94
- def write_standard_file(dir, content)
95
- write_file("#{dir}/.gitattributes", content)
96
- end
97
-
98
- def write_file(attributes_file, content)
99
- FileUtils.mkdir_p File.dirname(attributes_file)
100
- IO.write(attributes_file, content)
101
- end
102
- end