root/tags/release2_2/ftp_path.py

Revision 647, 6.2 kB (checked in by schwa, 2 years ago)
Turn classes into new-style classes by letting them inherit from
`object`.
  • Property svn:mime-type set to text/x-python
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1 # Copyright (C) 2003-2006, Stefan Schwarzer
2 # All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7 #
8 # - Redistributions of source code must retain the above copyright
9 #   notice, this list of conditions and the following disclaimer.
10 #
11 # - Redistributions in binary form must reproduce the above copyright
12 #   notice, this list of conditions and the following disclaimer in the
13 #   documentation and/or other materials provided with the distribution.
14 #
15 # - Neither the name of the above author nor the names of the
16 #   contributors to the software may be used to endorse or promote
17 #   products derived from this software without specific prior written
18 #   permission.
19 #
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
24 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32 """
33 ftp_path.py - simulate `os.path` for FTP servers
34 """
35
36 # $Id$
37
38 import posixpath
39 import stat
40
41 import ftp_error
42
43
44 class _Path(object):
45     """
46     Support class resembling `os.path`, accessible from the `FTPHost`
47     object, e. g. as `FTPHost().path.abspath(path)`.
48
49     Hint: substitute `os` with the `FTPHost` object.
50     """
51     def __init__(self, host):
52         self._host = host
53         # delegate these to the `posixpath` module
54         pp = posixpath
55         self.dirname      = pp.dirname
56         self.basename     = pp.basename
57         self.isabs        = pp.isabs
58         self.commonprefix = pp.commonprefix
59         self.join         = pp.join
60         self.split        = pp.split
61         self.splitdrive   = pp.splitdrive
62         self.splitext     = pp.splitext
63         self.normcase     = pp.normcase
64         self.normpath     = pp.normpath
65
66     def abspath(self, path):
67         """Return an absolute path."""
68         if not self.isabs(path):
69             path = self.join(self._host.getcwd(), path)
70         return self.normpath(path)
71
72     def exists(self, path):
73         try:
74             lstat_result = self._host.lstat(
75                            path, _exception_for_missing_path=False)
76             return lstat_result is not None
77         except ftp_error.RootDirError:
78             return True
79
80     def getmtime(self, path):
81         return self._host.stat(path).st_mtime
82
83     def getsize(self, path):
84         return self._host.stat(path).st_size
85
86     # check whether a path is a regular file/dir/link;
87     #  for the first two cases follow links (like in `os.path`)
88     #
89     # Implementation note: The previous implementations simply called
90     # `stat` or `lstat` and returned `False` if they ended with
91     # raising a `PermanentError`. That exception usually used to
92     # signal a missing path. This approach has the problem, however,
93     # that exceptions caused by code earlier in `lstat` are obscured
94     # by the exception handling in `isfile`, `isdir` and `islink`.
95
96     def isfile(self, path):
97         # workaround if we can't go up from the current directory
98         if path == self._host.getcwd():
99             return False
100         try:
101             stat_result = self._host.stat(
102                           path, _exception_for_missing_path=False)
103             if stat_result is None:
104                 return False
105             else:
106                 return stat.S_ISREG(stat_result.st_mode)
107         except ftp_error.RootDirError:
108             return False
109
110     def isdir(self, path):
111         # workaround if we can't go up from the current directory
112         if path == self._host.getcwd():
113             return True
114         try:
115             stat_result = self._host.stat(
116                           path, _exception_for_missing_path=False)
117             if stat_result is None:
118                 return False
119             else:
120                 return stat.S_ISDIR(stat_result.st_mode)
121         except ftp_error.RootDirError:
122             return True
123
124     def islink(self, path):
125         try:
126             lstat_result = self._host.lstat(
127                            path, _exception_for_missing_path=False)
128             if lstat_result is None:
129                 return False
130             else:
131                 return stat.S_ISLNK(lstat_result.st_mode)
132         except ftp_error.RootDirError:
133             return False
134
135     def walk(self, top, func, arg):
136         """
137         Directory tree walk with callback function.
138
139         For each directory in the directory tree rooted at top
140         (including top itself, but excluding '.' and '..'), call
141         func(arg, dirname, fnames). dirname is the name of the
142         directory, and fnames a list of the names of the files and
143         subdirectories in dirname (excluding '.' and '..').  func may
144         modify the fnames list in-place (e.g. via del or slice
145         assignment), and walk will only recurse into the
146         subdirectories whose names remain in fnames; this can be used
147         to implement a filter, or to impose a specific order of
148         visiting.  No semantics are defined for, or required of, arg,
149         beyond that arg is always passed to func.  It can be used,
150         e.g., to pass a filename pattern, or a mutable object designed
151         to accumulate statistics.  Passing None for arg is common.
152         """
153         # This code (and the above documentation) is taken from
154         #  posixpath.py, with slight modifications
155         try:
156             names = self._host.listdir(top)
157         except OSError:
158             return
159         func(arg, top, names)
160         for name in names:
161             name = self.join(top, name)
162             try:
163                 st = self._host.lstat(name)
164             except OSError:
165                 continue
166             if stat.S_ISDIR(st[stat.ST_MODE]):
167                 self.walk(name, func, arg)
168
Note: See TracBrowser for help on using the browser.