netrc 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
1
+ # Netrc
2
+
3
+ This library reads and writes `.netrc` files.
4
+
5
+ ## API
6
+
7
+ Read a netrc file:
8
+
9
+ n = Netrc.read("sample.netrc")
10
+
11
+ If the file doesn't exist, Netrc.read will return an empty object.
12
+
13
+ Read the user's default netrc file (`$HOME/.netrc` on Unix;
14
+ `%HOME%\_netrc` on Windows):
15
+
16
+ n = Netrc.read
17
+
18
+ Look up a username and password:
19
+
20
+ user, pass = n["example.com"]
21
+
22
+ Write a username and password:
23
+
24
+ n["example.com"] = user, newpass
25
+ n.save
26
+
27
+ If you make an entry that wasn't there before, it will be appended
28
+ to the end of the file. Sometimes people want to include a comment
29
+ explaining that the entry was added automatically. You can do it
30
+ like this:
31
+
32
+ n.new_item_prefix = "# This entry was added automatically\n"
33
+ n["example.com"] = user, newpass
34
+ n.save
35
+
36
+ Have fun!
37
+
38
+ ## Running Tests
39
+
40
+ $ turn test
@@ -0,0 +1,4 @@
1
+ # this is my netrc
2
+ machine m
3
+ login l # this is my username
4
+ password p
@@ -0,0 +1,4 @@
1
+ # this is my netrc
2
+ machine m
3
+ login l # this is my username
4
+ password p
@@ -0,0 +1,134 @@
1
+ class Netrc
2
+ VERSION = "0.1"
3
+
4
+ Windows = false
5
+ def self.default_path
6
+ File.join(ENV["HOME"], default_name)
7
+ end
8
+
9
+ def self.default_name
10
+ if Windows
11
+ return "_netrc"
12
+ end
13
+ ".netrc"
14
+ end
15
+
16
+ # Reads path and parses it as a .netrc file. If path doesn't
17
+ # exist, returns an empty object.
18
+ def self.read(path=default_path)
19
+ perm = File.stat(path).mode & 0777
20
+ if perm != 0600
21
+ raise Error, "Permission bits should be 0600, but are "+perm.to_s(8)
22
+ end
23
+ new(path, parse(lex(IO.readlines(path))))
24
+ rescue Errno::ENOENT
25
+ new(path, parse(lex([])))
26
+ end
27
+
28
+ def self.lex(lines)
29
+ tokens = []
30
+ for line in lines
31
+ content, comment = line.split(/(\s*#.*)/m)
32
+ tokens += content.split(/(?<=\s)(?=\S)|(?<=\S)(?=\s)/)
33
+ if comment
34
+ tokens << comment
35
+ end
36
+ end
37
+ tokens
38
+ end
39
+
40
+ def self.skip?(s)
41
+ s =~ /^\s/
42
+ end
43
+
44
+ # Returns two values, a header and a list of items.
45
+ # Each item is a 7-tuple, containing:
46
+ # - machine keyword (including trailing whitespace+comments)
47
+ # - machine name
48
+ # - login keyword (including surrounding whitespace+comments)
49
+ # - login
50
+ # - password keyword (including surrounding whitespace+comments)
51
+ # - password
52
+ # - trailing chars
53
+ # This lets us change individual fields, then write out the file
54
+ # with all its original formatting.
55
+ def self.parse(ts)
56
+ cur, item = [], []
57
+
58
+ def ts.take
59
+ if count < 1
60
+ raise Error, "unexpected EOF"
61
+ end
62
+ shift
63
+ end
64
+
65
+ def ts.readto
66
+ l = []
67
+ while count > 0 && ! yield(self[0])
68
+ l << shift
69
+ end
70
+ return l.join
71
+ end
72
+
73
+ pre = ts.readto{|t| t == "machine"}
74
+ while ts.count > 0
75
+ cur << ts.take + ts.readto{|t| ! skip?(t)}
76
+ cur << ts.take
77
+ cur << ts.readto{|t| t == "login"} + ts.take + ts.readto{|t| ! skip?(t)}
78
+ cur << ts.take
79
+ cur << ts.readto{|t| t == "password"} + ts.take + ts.readto{|t| ! skip?(t)}
80
+ cur << ts.take
81
+ cur << ts.readto{|t| t == "machine"}
82
+ item << cur
83
+ cur = []
84
+ end
85
+
86
+ [pre, item]
87
+ end
88
+
89
+ def initialize(path, data)
90
+ @path = path
91
+ @pre, @data = data
92
+ end
93
+
94
+ attr_accessor :new_item_prefix
95
+
96
+ def [](k)
97
+ for v in @data
98
+ if v[1] == k
99
+ return v[3], v[5]
100
+ end
101
+ end
102
+ nil
103
+ end
104
+
105
+ def []=(k, info)
106
+ for v in @data
107
+ if v[1] == k
108
+ v[3], v[5] = info
109
+ return
110
+ end
111
+ end
112
+ @data << new_item(k, info[0], info[1])
113
+ end
114
+
115
+ def count
116
+ @data.count
117
+ end
118
+
119
+ def new_item(m, l, p)
120
+ [new_item_prefix+"machine ", m, "\n login ", l, "\n password ", p, "\n"]
121
+ end
122
+
123
+ def save
124
+ File.write(path, unparse)
125
+ end
126
+
127
+ def unparse
128
+ @pre + @data.map(&:join).join
129
+ end
130
+
131
+ end
132
+
133
+ class Netrc::Error < ::StandardError
134
+ end
@@ -0,0 +1,52 @@
1
+ $VERBOSE = true
2
+ require 'minitest/autorun'
3
+
4
+ require 'netrc'
5
+
6
+ class TestLex < MiniTest::Unit::TestCase
7
+ def test_lex_empty
8
+ t = Netrc.lex([])
9
+ assert_equal([], t)
10
+ end
11
+
12
+ def test_lex_comment
13
+ t = Netrc.lex(["# foo\n"])
14
+ assert_equal(["# foo\n"], t)
15
+ end
16
+
17
+ def test_lex_comment_after_space
18
+ t = Netrc.lex([" # foo\n"])
19
+ assert_equal([" # foo\n"], t)
20
+ end
21
+
22
+ def test_lex_comment_after_word
23
+ t = Netrc.lex(["x # foo\n"])
24
+ assert_equal(["x", " # foo\n"], t)
25
+ end
26
+
27
+ def test_lex_comment_with_hash
28
+ t = Netrc.lex(["x # foo # bar\n"])
29
+ assert_equal(["x", " # foo # bar\n"], t)
30
+ end
31
+
32
+ def test_lex_word
33
+ t = Netrc.lex(["x"])
34
+ assert_equal(["x"], t)
35
+ end
36
+
37
+ def test_lex_two_lines
38
+ t = Netrc.lex(["x\ny\n"])
39
+ assert_equal(["x", "\n", "y", "\n"], t)
40
+ end
41
+
42
+ def test_lex_word_and_comment
43
+ t = Netrc.lex(["x\n", "# foo\n"])
44
+ assert_equal(["x", "\n", "# foo\n"], t)
45
+ end
46
+
47
+ def test_lex_six_words
48
+ t = Netrc.lex(["machine m login l password p\n"])
49
+ e = ["machine", " ", "m", " ", "login", " ", "l", " ", "password", " ", "p", "\n"]
50
+ assert_equal(e, t)
51
+ end
52
+ end
@@ -0,0 +1,90 @@
1
+ $VERBOSE = true
2
+ require 'minitest/autorun'
3
+
4
+ require 'netrc'
5
+
6
+ class TestNetrc < MiniTest::Unit::TestCase
7
+ def setup
8
+ File.chmod(0600, "data/sample.netrc")
9
+ File.chmod(0644, "data/permissive.netrc")
10
+ end
11
+
12
+ def test_parse_empty
13
+ pre, items = Netrc.parse(Netrc.lex([]))
14
+ assert_equal("", pre)
15
+ assert_equal([], items)
16
+ end
17
+
18
+ def test_parse_file
19
+ pre, items = Netrc.parse(Netrc.lex(IO.readlines("data/sample.netrc")))
20
+ assert_equal("# this is my netrc\n", pre)
21
+ exp = [["machine ",
22
+ "m",
23
+ "\n login ",
24
+ "l",
25
+ " # this is my username\n password ",
26
+ "p",
27
+ "\n"]]
28
+ assert_equal(exp, items)
29
+ end
30
+
31
+ def test_missing_file
32
+ n = Netrc.read("data/nonexistent.netrc")
33
+ assert_equal(0, n.count)
34
+ end
35
+
36
+ def test_permission_error
37
+ Netrc.read("data/permissive.netrc")
38
+ assert false, "Should raise an error if permissions are wrong."
39
+ rescue Netrc::Error
40
+ end
41
+
42
+ def test_round_trip
43
+ n = Netrc.read("data/sample.netrc")
44
+ assert_equal(IO.read("data/sample.netrc"), n.unparse)
45
+ end
46
+
47
+ def test_set
48
+ n = Netrc.read("data/sample.netrc")
49
+ n["m"] = "a", "b"
50
+ exp = "# this is my netrc\n"+
51
+ "machine m\n"+
52
+ " login a # this is my username\n"+
53
+ " password b\n"
54
+ assert_equal(exp, n.unparse)
55
+ end
56
+
57
+ def test_set_get
58
+ n = Netrc.read("data/sample.netrc")
59
+ n["m"] = "a", "b"
60
+ l, p = n["m"]
61
+ assert_equal(["a", "b"], n["m"])
62
+ end
63
+
64
+ def test_add
65
+ n = Netrc.read("data/sample.netrc")
66
+ n.new_item_prefix = "# added\n"
67
+ n["x"] = "a", "b"
68
+ exp = "# this is my netrc\n"+
69
+ "machine m\n"+
70
+ " login l # this is my username\n"+
71
+ " password p\n"+
72
+ "# added\n"+
73
+ "machine x\n"+
74
+ " login a\n"+
75
+ " password b\n"
76
+ assert_equal(exp, n.unparse)
77
+ end
78
+
79
+ def test_add_get
80
+ n = Netrc.read("data/sample.netrc")
81
+ n.new_item_prefix = "# added\n"
82
+ n["x"] = "a", "b"
83
+ assert_equal(["a", "b"], n["x"])
84
+ end
85
+
86
+ def test_get_missing
87
+ n = Netrc.read("data/sample.netrc")
88
+ assert_equal(nil, n["x"])
89
+ end
90
+ end
@@ -0,0 +1,34 @@
1
+ $VERBOSE = true
2
+ require 'minitest/autorun'
3
+
4
+ require 'netrc'
5
+
6
+ class TestParse < MiniTest::Unit::TestCase
7
+ def test_parse_empty
8
+ pre, items = Netrc.parse([])
9
+ assert_equal("", pre)
10
+ assert_equal([], items)
11
+ end
12
+
13
+ def test_parse_comment
14
+ pre, items = Netrc.parse(["# foo\n"])
15
+ assert_equal("# foo\n", pre)
16
+ assert_equal([], items)
17
+ end
18
+
19
+ def test_parse_item
20
+ t = ["machine", " ", "m", " ", "login", " ", "l", " ", "password", " ", "p", "\n"]
21
+ pre, items = Netrc.parse(t)
22
+ assert_equal("", pre)
23
+ e = [["machine ", "m", " login ", "l", " password ", "p", "\n"]]
24
+ assert_equal(e, items)
25
+ end
26
+
27
+ def test_parse_two_items
28
+ t = ["machine", " ", "m", " ", "login", " ", "l", " ", "password", " ", "p", "\n"] * 2
29
+ pre, items = Netrc.parse(t)
30
+ assert_equal("", pre)
31
+ e = [["machine ", "m", " login ", "l", " password ", "p", "\n"]] * 2
32
+ assert_equal(e, items)
33
+ end
34
+ end
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: netrc
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Keith Rarick
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-15 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: This library can read and update netrc files, preserving formatting including
15
+ comments and whitespace.
16
+ email: kr@xph.us
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - Readme.md
22
+ - data/permissive.netrc
23
+ - data/sample.netrc
24
+ - lib/netrc.rb
25
+ - test/test_lex.rb
26
+ - test/test_netrc.rb
27
+ - test/test_parse.rb
28
+ homepage: https://github.com/kr/netrc
29
+ licenses: []
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubyforge_project:
48
+ rubygems_version: 1.8.10
49
+ signing_key:
50
+ specification_version: 3
51
+ summary: Library to read and write netrc files.
52
+ test_files: []