[50fdf12] | 1 | # |
---|
| 2 | # RTEMS Tools Project (http://www.rtems.org/) |
---|
| 3 | # Copyright 2010-2014 Chris Johns (chrisj@rtems.org) |
---|
| 4 | # All rights reserved. |
---|
| 5 | # |
---|
| 6 | # This file is part of the RTEMS Tools package in 'rtems-tools'. |
---|
| 7 | # |
---|
| 8 | # Redistribution and use in source and binary forms, with or without |
---|
| 9 | # modification, are permitted provided that the following conditions are met: |
---|
| 10 | # |
---|
| 11 | # 1. Redistributions of source code must retain the above copyright notice, |
---|
| 12 | # this list of conditions and the following disclaimer. |
---|
| 13 | # |
---|
| 14 | # 2. Redistributions in binary form must reproduce the above copyright notice, |
---|
| 15 | # this list of conditions and the following disclaimer in the documentation |
---|
| 16 | # and/or other materials provided with the distribution. |
---|
| 17 | # |
---|
| 18 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
---|
| 19 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
| 20 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
| 21 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
---|
| 22 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
---|
| 23 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
---|
| 24 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
---|
| 25 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
---|
| 26 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
---|
| 27 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
---|
| 28 | # POSSIBILITY OF SUCH DAMAGE. |
---|
| 29 | # |
---|
| 30 | |
---|
| 31 | # |
---|
| 32 | # Manage paths locally. The internally the path is in Unix or shell format and |
---|
| 33 | # we convert to the native format when performing operations at the Python |
---|
| 34 | # level. This allows macro expansion to work. |
---|
| 35 | # |
---|
| 36 | |
---|
| 37 | import glob |
---|
| 38 | import os |
---|
| 39 | import shutil |
---|
| 40 | import string |
---|
| 41 | |
---|
[de1beea] | 42 | import error |
---|
| 43 | import log |
---|
[50fdf12] | 44 | |
---|
| 45 | windows = os.name == 'nt' |
---|
| 46 | |
---|
| 47 | def host(path): |
---|
| 48 | if path is not None: |
---|
| 49 | while '//' in path: |
---|
| 50 | path = path.replace('//', '/') |
---|
| 51 | if windows and len(path) > 2: |
---|
| 52 | if path[0] == '/' and path[2] == '/' and \ |
---|
| 53 | (path[1] in string.ascii_lowercase or \ |
---|
| 54 | path[1] in string.ascii_uppercase): |
---|
| 55 | path = ('%s:%s' % (path[1], path[2:])).replace('/', '\\') |
---|
| 56 | return path |
---|
| 57 | |
---|
| 58 | def shell(path): |
---|
| 59 | if path is not None: |
---|
| 60 | if windows and len(path) > 1 and path[1] == ':': |
---|
| 61 | path = ('/%s%s' % (path[0], path[2:])).replace('\\', '/') |
---|
| 62 | while '//' in path: |
---|
| 63 | path = path.replace('//', '/') |
---|
| 64 | return path |
---|
| 65 | |
---|
| 66 | def basename(path): |
---|
| 67 | return shell(os.path.basename(path)) |
---|
| 68 | |
---|
| 69 | def dirname(path): |
---|
| 70 | return shell(os.path.dirname(path)) |
---|
| 71 | |
---|
| 72 | def join(path, *args): |
---|
| 73 | path = shell(path) |
---|
| 74 | for arg in args: |
---|
| 75 | if len(path): |
---|
| 76 | path += '/' + shell(arg) |
---|
| 77 | else: |
---|
| 78 | path = shell(arg) |
---|
| 79 | return shell(path) |
---|
| 80 | |
---|
| 81 | def abspath(path): |
---|
| 82 | return shell(os.path.abspath(host(path))) |
---|
| 83 | |
---|
| 84 | def splitext(path): |
---|
| 85 | root, ext = os.path.splitext(host(path)) |
---|
| 86 | return shell(root), ext |
---|
| 87 | |
---|
| 88 | def exists(paths): |
---|
| 89 | if type(paths) == list: |
---|
| 90 | results = [] |
---|
| 91 | for p in paths: |
---|
| 92 | results += [os.path.exists(host(p))] |
---|
| 93 | return results |
---|
| 94 | return os.path.exists(host(paths)) |
---|
| 95 | |
---|
| 96 | def isdir(path): |
---|
| 97 | return os.path.isdir(host(path)) |
---|
| 98 | |
---|
| 99 | def isfile(path): |
---|
| 100 | return os.path.isfile(host(path)) |
---|
| 101 | |
---|
| 102 | def isabspath(path): |
---|
| 103 | return path[0] == '/' |
---|
| 104 | |
---|
| 105 | def iswritable(path): |
---|
| 106 | return os.access(host(path), os.W_OK) |
---|
| 107 | |
---|
| 108 | def ispathwritable(path): |
---|
| 109 | path = host(path) |
---|
| 110 | while len(path) != 0: |
---|
| 111 | if os.path.exists(path): |
---|
| 112 | return iswritable(path) |
---|
| 113 | path = os.path.dirname(path) |
---|
| 114 | return False |
---|
| 115 | |
---|
| 116 | def mkdir(path): |
---|
| 117 | path = host(path) |
---|
| 118 | if exists(path): |
---|
| 119 | if not isdir(path): |
---|
| 120 | raise error.general('path exists and is not a directory: %s' % (path)) |
---|
| 121 | else: |
---|
| 122 | if windows: |
---|
| 123 | try: |
---|
| 124 | os.makedirs(host(path)) |
---|
[04a5204] | 125 | except IOError: |
---|
[50fdf12] | 126 | raise error.general('cannot make directory: %s' % (path)) |
---|
[04a5204] | 127 | except OSError: |
---|
[50fdf12] | 128 | raise error.general('cannot make directory: %s' % (path)) |
---|
[04a5204] | 129 | except WindowsError: |
---|
[50fdf12] | 130 | raise error.general('cannot make directory: %s' % (path)) |
---|
| 131 | else: |
---|
| 132 | try: |
---|
| 133 | os.makedirs(host(path)) |
---|
[04a5204] | 134 | except IOError: |
---|
[50fdf12] | 135 | raise error.general('cannot make directory: %s' % (path)) |
---|
[04a5204] | 136 | except OSError: |
---|
[50fdf12] | 137 | raise error.general('cannot make directory: %s' % (path)) |
---|
| 138 | |
---|
| 139 | def removeall(path): |
---|
| 140 | |
---|
| 141 | def _onerror(function, path, excinfo): |
---|
[04a5204] | 142 | print('removeall error: (%s) %s' % (excinfo, path)) |
---|
[50fdf12] | 143 | |
---|
| 144 | path = host(path) |
---|
| 145 | shutil.rmtree(path, onerror = _onerror) |
---|
| 146 | return |
---|
| 147 | |
---|
| 148 | def expand(name, paths): |
---|
| 149 | l = [] |
---|
| 150 | for p in paths: |
---|
| 151 | l += [join(p, name)] |
---|
| 152 | return l |
---|
| 153 | |
---|
| 154 | def collect_files(path_): |
---|
| 155 | # |
---|
| 156 | # Convert to shell paths and return shell paths. |
---|
| 157 | # |
---|
| 158 | # @fixme should this use a passed in set of defaults and not |
---|
| 159 | # not the initial set of values ? |
---|
| 160 | # |
---|
| 161 | path_ = shell(path_) |
---|
| 162 | if '*' in path_ or '?' in path_: |
---|
| 163 | dir = dirname(path_) |
---|
| 164 | base = basename(path_) |
---|
| 165 | if len(base) == 0: |
---|
| 166 | base = '*' |
---|
| 167 | files = [] |
---|
| 168 | for p in dir.split(':'): |
---|
| 169 | hostdir = host(p) |
---|
| 170 | for f in glob.glob(os.path.join(hostdir, base)): |
---|
| 171 | files += [host(f)] |
---|
| 172 | else: |
---|
| 173 | files = [host(path_)] |
---|
| 174 | return sorted(files) |
---|
| 175 | |
---|
| 176 | def copy_tree(src, dst): |
---|
| 177 | hsrc = host(src) |
---|
| 178 | hdst = host(dst) |
---|
| 179 | |
---|
| 180 | if os.path.exists(src): |
---|
| 181 | names = os.listdir(src) |
---|
| 182 | else: |
---|
| 183 | name = [] |
---|
| 184 | |
---|
| 185 | if not os.path.isdir(dst): |
---|
| 186 | os.makedirs(dst) |
---|
| 187 | |
---|
| 188 | for name in names: |
---|
| 189 | srcname = os.path.join(src, name) |
---|
| 190 | dstname = os.path.join(dst, name) |
---|
| 191 | try: |
---|
| 192 | if os.path.islink(srcname): |
---|
| 193 | linkto = os.readlink(srcname) |
---|
| 194 | if os.path.exists(dstname): |
---|
| 195 | if os.path.islink(dstname): |
---|
| 196 | dstlinkto = os.readlink(dstname) |
---|
| 197 | if linkto != dstlinkto: |
---|
| 198 | log.warning('copying tree: update of link does not match: %s -> %s' % \ |
---|
| 199 | (dstname, dstlinkto)) |
---|
| 200 | os.remove(dstname) |
---|
| 201 | else: |
---|
| 202 | log.warning('copying tree: destination is not a link: %s' % \ |
---|
| 203 | (dstname)) |
---|
| 204 | os.remove(dstname) |
---|
| 205 | else: |
---|
| 206 | os.symlink(linkto, dstname) |
---|
| 207 | elif os.path.isdir(srcname): |
---|
| 208 | copy_tree(srcname, dstname) |
---|
| 209 | else: |
---|
| 210 | shutil.copy2(srcname, dstname) |
---|
[04a5204] | 211 | except shutil.Error as err: |
---|
[50fdf12] | 212 | raise error.general('copying tree: %s -> %s: %s' % (src, dst, str(err))) |
---|
[04a5204] | 213 | except EnvironmentError as why: |
---|
[50fdf12] | 214 | raise error.general('copying tree: %s -> %s: %s' % (srcname, dstname, str(why))) |
---|
| 215 | try: |
---|
| 216 | shutil.copystat(src, dst) |
---|
[04a5204] | 217 | except OSError as why: |
---|
[50fdf12] | 218 | ok = False |
---|
| 219 | if windows: |
---|
| 220 | if WindowsError is not None and isinstance(why, WindowsError): |
---|
| 221 | ok = True |
---|
| 222 | if not ok: |
---|
| 223 | raise error.general('copying tree: %s -> %s: %s' % (src, dst, str(why))) |
---|
| 224 | |
---|
| 225 | if __name__ == '__main__': |
---|
[04a5204] | 226 | print(host('/a/b/c/d-e-f')) |
---|
| 227 | print(host('//a/b//c/d-e-f')) |
---|
| 228 | print(shell('/w/x/y/z')) |
---|
| 229 | print(basename('/as/sd/df/fg/me.txt')) |
---|
| 230 | print(dirname('/as/sd/df/fg/me.txt')) |
---|
| 231 | print(join('/d', 'g', '/tyty/fgfg')) |
---|
[50fdf12] | 232 | windows = True |
---|
[04a5204] | 233 | print(host('/a/b/c/d-e-f')) |
---|
| 234 | print(host('//a/b//c/d-e-f')) |
---|
| 235 | print(shell('/w/x/y/z')) |
---|
| 236 | print(shell('w:/x/y/z')) |
---|
| 237 | print(basename('x:/sd/df/fg/me.txt')) |
---|
| 238 | print(dirname('x:/sd/df/fg/me.txt')) |
---|
| 239 | print(join('s:/d/', '/g', '/tyty/fgfg')) |
---|