[50fdf12] | 1 | # |
---|
| 2 | # RTEMS Tools Project (http://www.rtems.org/) |
---|
[b0fa2ae] | 3 | # Copyright 2010-2016 Chris Johns (chrisj@rtems.org) |
---|
[50fdf12] | 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 | |
---|
[b0fa2ae] | 37 | from __future__ import print_function |
---|
| 38 | |
---|
[50fdf12] | 39 | import glob |
---|
| 40 | import os |
---|
| 41 | import shutil |
---|
| 42 | import string |
---|
| 43 | |
---|
[b0fa2ae] | 44 | # |
---|
| 45 | # Support to handle use in a package and as a unit test. |
---|
| 46 | # If there is a better way to let us know. |
---|
| 47 | # |
---|
| 48 | try: |
---|
| 49 | from . import error |
---|
| 50 | from . import log |
---|
| 51 | except (ValueError, SystemError): |
---|
| 52 | import error |
---|
| 53 | import log |
---|
[50fdf12] | 54 | |
---|
| 55 | windows = os.name == 'nt' |
---|
| 56 | |
---|
| 57 | def host(path): |
---|
| 58 | if path is not None: |
---|
| 59 | while '//' in path: |
---|
| 60 | path = path.replace('//', '/') |
---|
| 61 | if windows and len(path) > 2: |
---|
| 62 | if path[0] == '/' and path[2] == '/' and \ |
---|
| 63 | (path[1] in string.ascii_lowercase or \ |
---|
| 64 | path[1] in string.ascii_uppercase): |
---|
| 65 | path = ('%s:%s' % (path[1], path[2:])).replace('/', '\\') |
---|
| 66 | return path |
---|
| 67 | |
---|
| 68 | def shell(path): |
---|
| 69 | if path is not None: |
---|
| 70 | if windows and len(path) > 1 and path[1] == ':': |
---|
| 71 | path = ('/%s%s' % (path[0], path[2:])).replace('\\', '/') |
---|
| 72 | while '//' in path: |
---|
| 73 | path = path.replace('//', '/') |
---|
| 74 | return path |
---|
| 75 | |
---|
| 76 | def basename(path): |
---|
| 77 | return shell(os.path.basename(path)) |
---|
| 78 | |
---|
| 79 | def dirname(path): |
---|
| 80 | return shell(os.path.dirname(path)) |
---|
| 81 | |
---|
| 82 | def join(path, *args): |
---|
| 83 | path = shell(path) |
---|
| 84 | for arg in args: |
---|
| 85 | if len(path): |
---|
| 86 | path += '/' + shell(arg) |
---|
| 87 | else: |
---|
| 88 | path = shell(arg) |
---|
| 89 | return shell(path) |
---|
| 90 | |
---|
| 91 | def abspath(path): |
---|
| 92 | return shell(os.path.abspath(host(path))) |
---|
| 93 | |
---|
| 94 | def splitext(path): |
---|
| 95 | root, ext = os.path.splitext(host(path)) |
---|
| 96 | return shell(root), ext |
---|
| 97 | |
---|
| 98 | def exists(paths): |
---|
| 99 | if type(paths) == list: |
---|
| 100 | results = [] |
---|
| 101 | for p in paths: |
---|
| 102 | results += [os.path.exists(host(p))] |
---|
| 103 | return results |
---|
| 104 | return os.path.exists(host(paths)) |
---|
| 105 | |
---|
| 106 | def isdir(path): |
---|
| 107 | return os.path.isdir(host(path)) |
---|
| 108 | |
---|
| 109 | def isfile(path): |
---|
| 110 | return os.path.isfile(host(path)) |
---|
| 111 | |
---|
| 112 | def isabspath(path): |
---|
| 113 | return path[0] == '/' |
---|
| 114 | |
---|
| 115 | def iswritable(path): |
---|
| 116 | return os.access(host(path), os.W_OK) |
---|
| 117 | |
---|
| 118 | def ispathwritable(path): |
---|
| 119 | path = host(path) |
---|
| 120 | while len(path) != 0: |
---|
| 121 | if os.path.exists(path): |
---|
| 122 | return iswritable(path) |
---|
| 123 | path = os.path.dirname(path) |
---|
| 124 | return False |
---|
| 125 | |
---|
| 126 | def mkdir(path): |
---|
| 127 | path = host(path) |
---|
| 128 | if exists(path): |
---|
| 129 | if not isdir(path): |
---|
| 130 | raise error.general('path exists and is not a directory: %s' % (path)) |
---|
| 131 | else: |
---|
| 132 | if windows: |
---|
| 133 | try: |
---|
| 134 | os.makedirs(host(path)) |
---|
[04a5204] | 135 | except IOError: |
---|
[50fdf12] | 136 | raise error.general('cannot make directory: %s' % (path)) |
---|
[04a5204] | 137 | except OSError: |
---|
[50fdf12] | 138 | raise error.general('cannot make directory: %s' % (path)) |
---|
[04a5204] | 139 | except WindowsError: |
---|
[50fdf12] | 140 | raise error.general('cannot make directory: %s' % (path)) |
---|
| 141 | else: |
---|
| 142 | try: |
---|
| 143 | os.makedirs(host(path)) |
---|
[04a5204] | 144 | except IOError: |
---|
[50fdf12] | 145 | raise error.general('cannot make directory: %s' % (path)) |
---|
[04a5204] | 146 | except OSError: |
---|
[50fdf12] | 147 | raise error.general('cannot make directory: %s' % (path)) |
---|
| 148 | |
---|
| 149 | def removeall(path): |
---|
| 150 | |
---|
| 151 | def _onerror(function, path, excinfo): |
---|
[04a5204] | 152 | print('removeall error: (%s) %s' % (excinfo, path)) |
---|
[50fdf12] | 153 | |
---|
| 154 | path = host(path) |
---|
| 155 | shutil.rmtree(path, onerror = _onerror) |
---|
| 156 | |
---|
| 157 | def expand(name, paths): |
---|
| 158 | l = [] |
---|
| 159 | for p in paths: |
---|
| 160 | l += [join(p, name)] |
---|
| 161 | return l |
---|
| 162 | |
---|
[bf58911] | 163 | def expanduser(path): |
---|
| 164 | path = host(path) |
---|
| 165 | path = os.path.expanduser(path) |
---|
| 166 | return shell(path) |
---|
| 167 | |
---|
[50fdf12] | 168 | def collect_files(path_): |
---|
| 169 | # |
---|
| 170 | # Convert to shell paths and return shell paths. |
---|
| 171 | # |
---|
| 172 | # @fixme should this use a passed in set of defaults and not |
---|
| 173 | # not the initial set of values ? |
---|
| 174 | # |
---|
| 175 | path_ = shell(path_) |
---|
| 176 | if '*' in path_ or '?' in path_: |
---|
| 177 | dir = dirname(path_) |
---|
| 178 | base = basename(path_) |
---|
| 179 | if len(base) == 0: |
---|
| 180 | base = '*' |
---|
| 181 | files = [] |
---|
| 182 | for p in dir.split(':'): |
---|
| 183 | hostdir = host(p) |
---|
| 184 | for f in glob.glob(os.path.join(hostdir, base)): |
---|
| 185 | files += [host(f)] |
---|
| 186 | else: |
---|
| 187 | files = [host(path_)] |
---|
| 188 | return sorted(files) |
---|
| 189 | |
---|
| 190 | def copy_tree(src, dst): |
---|
| 191 | hsrc = host(src) |
---|
| 192 | hdst = host(dst) |
---|
| 193 | |
---|
| 194 | if os.path.exists(src): |
---|
| 195 | names = os.listdir(src) |
---|
| 196 | else: |
---|
| 197 | name = [] |
---|
| 198 | |
---|
| 199 | if not os.path.isdir(dst): |
---|
| 200 | os.makedirs(dst) |
---|
| 201 | |
---|
| 202 | for name in names: |
---|
| 203 | srcname = os.path.join(src, name) |
---|
| 204 | dstname = os.path.join(dst, name) |
---|
| 205 | try: |
---|
| 206 | if os.path.islink(srcname): |
---|
| 207 | linkto = os.readlink(srcname) |
---|
| 208 | if os.path.exists(dstname): |
---|
| 209 | if os.path.islink(dstname): |
---|
| 210 | dstlinkto = os.readlink(dstname) |
---|
| 211 | if linkto != dstlinkto: |
---|
| 212 | log.warning('copying tree: update of link does not match: %s -> %s' % \ |
---|
| 213 | (dstname, dstlinkto)) |
---|
| 214 | os.remove(dstname) |
---|
| 215 | else: |
---|
| 216 | log.warning('copying tree: destination is not a link: %s' % \ |
---|
| 217 | (dstname)) |
---|
| 218 | os.remove(dstname) |
---|
| 219 | else: |
---|
| 220 | os.symlink(linkto, dstname) |
---|
| 221 | elif os.path.isdir(srcname): |
---|
| 222 | copy_tree(srcname, dstname) |
---|
| 223 | else: |
---|
| 224 | shutil.copy2(srcname, dstname) |
---|
[04a5204] | 225 | except shutil.Error as err: |
---|
[50fdf12] | 226 | raise error.general('copying tree: %s -> %s: %s' % (src, dst, str(err))) |
---|
[04a5204] | 227 | except EnvironmentError as why: |
---|
[50fdf12] | 228 | raise error.general('copying tree: %s -> %s: %s' % (srcname, dstname, str(why))) |
---|
| 229 | try: |
---|
| 230 | shutil.copystat(src, dst) |
---|
[04a5204] | 231 | except OSError as why: |
---|
[50fdf12] | 232 | ok = False |
---|
| 233 | if windows: |
---|
| 234 | if WindowsError is not None and isinstance(why, WindowsError): |
---|
| 235 | ok = True |
---|
| 236 | if not ok: |
---|
| 237 | raise error.general('copying tree: %s -> %s: %s' % (src, dst, str(why))) |
---|
| 238 | |
---|
| 239 | if __name__ == '__main__': |
---|
[04a5204] | 240 | print(host('/a/b/c/d-e-f')) |
---|
| 241 | print(host('//a/b//c/d-e-f')) |
---|
| 242 | print(shell('/w/x/y/z')) |
---|
| 243 | print(basename('/as/sd/df/fg/me.txt')) |
---|
| 244 | print(dirname('/as/sd/df/fg/me.txt')) |
---|
| 245 | print(join('/d', 'g', '/tyty/fgfg')) |
---|
[50fdf12] | 246 | windows = True |
---|
[04a5204] | 247 | print(host('/a/b/c/d-e-f')) |
---|
| 248 | print(host('//a/b//c/d-e-f')) |
---|
| 249 | print(shell('/w/x/y/z')) |
---|
| 250 | print(shell('w:/x/y/z')) |
---|
| 251 | print(basename('x:/sd/df/fg/me.txt')) |
---|
| 252 | print(dirname('x:/sd/df/fg/me.txt')) |
---|
| 253 | print(join('s:/d/', '/g', '/tyty/fgfg')) |
---|