netrc 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.
@@ -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: []