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.
- data/Readme.md +40 -0
- data/data/permissive.netrc +4 -0
- data/data/sample.netrc +4 -0
- data/lib/netrc.rb +134 -0
- data/test/test_lex.rb +52 -0
- data/test/test_netrc.rb +90 -0
- data/test/test_parse.rb +34 -0
- metadata +52 -0
data/Readme.md
ADDED
@@ -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
|
data/data/sample.netrc
ADDED
data/lib/netrc.rb
ADDED
@@ -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
|
data/test/test_lex.rb
ADDED
@@ -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
|
data/test/test_netrc.rb
ADDED
@@ -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
|
data/test/test_parse.rb
ADDED
@@ -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: []
|