|
1 """An object-oriented interface to .netrc files.""" |
|
2 |
|
3 # Module and documentation by Eric S. Raymond, 21 Dec 1998 |
|
4 |
|
5 import os, shlex |
|
6 |
|
7 __all__ = ["netrc", "NetrcParseError"] |
|
8 |
|
9 |
|
10 class NetrcParseError(Exception): |
|
11 """Exception raised on syntax errors in the .netrc file.""" |
|
12 def __init__(self, msg, filename=None, lineno=None): |
|
13 self.filename = filename |
|
14 self.lineno = lineno |
|
15 self.msg = msg |
|
16 Exception.__init__(self, msg) |
|
17 |
|
18 def __str__(self): |
|
19 return "%s (%s, line %s)" % (self.msg, self.filename, self.lineno) |
|
20 |
|
21 |
|
22 class netrc: |
|
23 def __init__(self, file=None): |
|
24 if file is None: |
|
25 try: |
|
26 file = os.path.join(os.environ['HOME'], ".netrc") |
|
27 except KeyError: |
|
28 raise IOError("Could not find .netrc: $HOME is not set") |
|
29 fp = open(file) |
|
30 self.hosts = {} |
|
31 self.macros = {} |
|
32 lexer = shlex.shlex(fp) |
|
33 lexer.wordchars += r"""!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~""" |
|
34 while 1: |
|
35 # Look for a machine, default, or macdef top-level keyword |
|
36 toplevel = tt = lexer.get_token() |
|
37 if not tt: |
|
38 break |
|
39 elif tt == 'machine': |
|
40 entryname = lexer.get_token() |
|
41 elif tt == 'default': |
|
42 entryname = 'default' |
|
43 elif tt == 'macdef': # Just skip to end of macdefs |
|
44 entryname = lexer.get_token() |
|
45 self.macros[entryname] = [] |
|
46 lexer.whitespace = ' \t' |
|
47 while 1: |
|
48 line = lexer.instream.readline() |
|
49 if not line or line == '\012': |
|
50 lexer.whitespace = ' \t\r\n' |
|
51 break |
|
52 self.macros[entryname].append(line) |
|
53 continue |
|
54 else: |
|
55 raise NetrcParseError( |
|
56 "bad toplevel token %r" % tt, file, lexer.lineno) |
|
57 |
|
58 # We're looking at start of an entry for a named machine or default. |
|
59 login = '' |
|
60 account = password = None |
|
61 self.hosts[entryname] = {} |
|
62 while 1: |
|
63 tt = lexer.get_token() |
|
64 if (tt=='' or tt == 'machine' or |
|
65 tt == 'default' or tt =='macdef'): |
|
66 if password: |
|
67 self.hosts[entryname] = (login, account, password) |
|
68 lexer.push_token(tt) |
|
69 break |
|
70 else: |
|
71 raise NetrcParseError( |
|
72 "malformed %s entry %s terminated by %s" |
|
73 % (toplevel, entryname, repr(tt)), |
|
74 file, lexer.lineno) |
|
75 elif tt == 'login' or tt == 'user': |
|
76 login = lexer.get_token() |
|
77 elif tt == 'account': |
|
78 account = lexer.get_token() |
|
79 elif tt == 'password': |
|
80 password = lexer.get_token() |
|
81 else: |
|
82 raise NetrcParseError("bad follower token %r" % tt, |
|
83 file, lexer.lineno) |
|
84 |
|
85 def authenticators(self, host): |
|
86 """Return a (user, account, password) tuple for given host.""" |
|
87 if host in self.hosts: |
|
88 return self.hosts[host] |
|
89 elif 'default' in self.hosts: |
|
90 return self.hosts['default'] |
|
91 else: |
|
92 return None |
|
93 |
|
94 def __repr__(self): |
|
95 """Dump the class data in the format of a .netrc file.""" |
|
96 rep = "" |
|
97 for host in self.hosts.keys(): |
|
98 attrs = self.hosts[host] |
|
99 rep = rep + "machine "+ host + "\n\tlogin " + repr(attrs[0]) + "\n" |
|
100 if attrs[1]: |
|
101 rep = rep + "account " + repr(attrs[1]) |
|
102 rep = rep + "\tpassword " + repr(attrs[2]) + "\n" |
|
103 for macro in self.macros.keys(): |
|
104 rep = rep + "macdef " + macro + "\n" |
|
105 for line in self.macros[macro]: |
|
106 rep = rep + line |
|
107 rep = rep + "\n" |
|
108 return rep |
|
109 |
|
110 if __name__ == '__main__': |
|
111 print netrc() |