source: rtems-source-builder/source-builder/sb/path.py @ 2c0676d

4.11
Last change on this file since 2c0676d was 2c0676d, checked in by Chris Johns <chrisj@…>, on 04/13/18 at 03:02:51

sb/path: Walk up to root checking if a path is writable.

A dirname of / is / so the path will never have a length of 0.

Close #3393

  • Property mode set to 100644
File size: 9.6 KB
RevLine 
[ab8319a]1#
2# RTEMS Tools Project (http://www.rtems.org/)
[f88fcf3]3# Copyright 2010-2016 Chris Johns (chrisj@rtems.org)
[ab8319a]4# All rights reserved.
5#
6# This file is part of the RTEMS Tools package in 'rtems-tools'.
7#
8# Permission to use, copy, modify, and/or distribute this software for any
9# purpose with or without fee is hereby granted, provided that the above
10# copyright notice and this permission notice appear in all copies.
11#
12# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20#
21# Manage paths locally. The internally the path is in Unix or shell format and
22# we convert to the native format when performing operations at the Python
23# level. This allows macro expansion to work.
24#
25
[f88fcf3]26from __future__ import print_function
27
[5e536f8]28import log
[ab8319a]29import os
[ee47d72]30import shutil
[a84249d]31import stat
[ab8319a]32import string
33
[ee47d72]34import error
35
[ab8319a]36windows = os.name == 'nt'
[78c1524]37win_maxpath = 254
[ab8319a]38
39def host(path):
40    if path is not None:
41        while '//' in path:
42            path = path.replace('//', '/')
[a84249d]43        if windows:
44            if len(path) > 2 and \
45               path[0] == '/' and path[2] == '/' and \
46               (path[1] in string.ascii_lowercase or \
47                path[1] in string.ascii_uppercase):
48                path = '%s:%s' % (path[1], path[2:])
49            path = path.replace('/', '\\')
[78c1524]50            if len(path) > win_maxpath:
51                if path.startswith('\\\\?\\'):
52                    path = path[4:]
53                path = u'\\'.join([u'\\\\?', path])
[ab8319a]54    return path
55
[e1346e2]56def is_abspath(path):
57    if path is not None:
58        return '/' == path[0]
59    return False
60
[ab8319a]61def shell(path):
62    if path is not None:
[a84249d]63        if windows:
[78c1524]64            path = path.encode('ascii', 'ignore')
[a84249d]65            if path.startswith('\\\\?\\'):
66                path = path[4:]
67            if len(path) > 1 and path[1] == ':':
68                path = '/%s%s' % (path[0], path[2:])
69            path = path.replace('\\', '/')
[ab8319a]70        while '//' in path:
71            path = path.replace('//', '/')
72    return path
73
74def basename(path):
[e1346e2]75    path = shell(path)
76    return shell(os.path.basename(host(path)))
[ab8319a]77
78def dirname(path):
[e1346e2]79    path = shell(path)
[ab8319a]80    return shell(os.path.dirname(path))
81
82def join(path, *args):
83    path = shell(path)
84    for arg in args:
[73e8afb]85        if len(path):
86            path += '/' + shell(arg)
87        else:
88            path = shell(arg)
[ab8319a]89    return shell(path)
90
91def abspath(path):
[e1346e2]92    path = shell(path)
[ab8319a]93    return shell(os.path.abspath(host(path)))
94
[e1346e2]95def relpath(path, start = None):
96    path = shell(path)
97    if start is None:
98        path = os.path.relpath(host(path))
99    else:
100        path = os.path.relpath(host(path), start)
101    return shell(path)
102
[ab8319a]103def splitext(path):
[e1346e2]104    path = shell(path)
[ab8319a]105    root, ext = os.path.splitext(host(path))
106    return shell(root), ext
107
[78c1524]108def listdir(path):
[e1346e2]109    path = shell(path)
[78c1524]110    hp = host(path)
111    if not os.path.exists(hp):
112        return []
113    return os.listdir(hp)
114
[06dad0a]115def exists(paths):
[78c1524]116    def _exists(p):
[e1346e2]117        if not is_abspath(p):
118            p = shell(join(os.getcwd(), host(p)))
119        return basename(p) in ['.'] + listdir(dirname(p))
[78c1524]120
[06dad0a]121    if type(paths) == list:
122        results = []
123        for p in paths:
[e1346e2]124            results += [_exists(shell(p))]
[06dad0a]125        return results
[e1346e2]126    return _exists(shell(paths))
[ab8319a]127
128def isdir(path):
[e1346e2]129    path = shell(path)
[ab8319a]130    return os.path.isdir(host(path))
131
132def isfile(path):
[e1346e2]133    path = shell(path)
[ab8319a]134    return os.path.isfile(host(path))
135
[8f84a6b]136def isabspath(path):
[e1346e2]137    path = shell(path)
[8f84a6b]138    return path[0] == '/'
139
[9994530]140def iswritable(path):
[e1346e2]141    path = shell(path)
[9994530]142    return os.access(host(path), os.W_OK)
143
[255e032]144def ispathwritable(path):
[e1346e2]145    path = shell(path)
[2c0676d]146    while len(path) > 1:
[78c1524]147        if exists(path):
[255e032]148            return iswritable(path)
[e1346e2]149        path = dirname(path)
[255e032]150    return False
151
[ee47d72]152def mkdir(path):
[e1346e2]153    path = shell(path)
[ee47d72]154    if exists(path):
155        if not isdir(path):
156            raise error.general('path exists and is not a directory: %s' % (path))
157    else:
158        if windows:
159            try:
160                os.makedirs(host(path))
[f88fcf3]161            except IOError as err:
[ee47d72]162                raise error.general('cannot make directory: %s' % (path))
[f88fcf3]163            except OSError as err:
[ee47d72]164                raise error.general('cannot make directory: %s' % (path))
[f88fcf3]165            except WindowsError as err:
[ee47d72]166                raise error.general('cannot make directory: %s' % (path))
167        else:
168            try:
169                os.makedirs(host(path))
[f88fcf3]170            except IOError as err:
[ee47d72]171                raise error.general('cannot make directory: %s' % (path))
[f88fcf3]172            except OSError as err:
[ee47d72]173                raise error.general('cannot make directory: %s' % (path))
174
[78c1524]175def chdir(path):
[e1346e2]176    path = shell(path)
[78c1524]177    os.chdir(host(path))
178
[ee47d72]179def removeall(path):
[a84249d]180    #
181    # Perform the removal of the directory tree manually so we can
[78c1524]182    # make sure on Windows the files are correctly encoded to avoid
183    # the file name size limit. On Windows the os.walk fails once we
184    # get to the max path length on Windows.
[a84249d]185    #
[78c1524]186    def _isdir(path):
187        hpath = host(path)
188        return os.path.isdir(hpath) and not os.path.islink(hpath)
189
190    def _remove_node(path):
191        hpath = host(path)
192        if not os.path.islink(hpath) and not os.access(hpath, os.W_OK):
193            os.chmod(hpath, stat.S_IWUSR)
194        if _isdir(path):
195            os.rmdir(hpath)
196        else:
197            os.unlink(hpath)
198
199    def _remove(path):
200        dirs = []
201        for name in listdir(path):
202            path_ = join(path, name)
203            hname = host(path_)
204            if _isdir(path_):
205                dirs += [name]
[88cb50a]206            else:
[78c1524]207                _remove_node(path_)
208        for name in dirs:
209            dir = join(path, name)
210            _remove(dir)
211            _remove_node(dir)
212
[e1346e2]213    path = shell(path)
[78c1524]214    hpath = host(path)
215
216    if os.path.exists(hpath):
217        _remove(path)
218        _remove_node(path)
[ee47d72]219
[06dad0a]220def expand(name, paths):
[e1346e2]221    path = shell(path)
[06dad0a]222    l = []
223    for p in paths:
[e1346e2]224        l += [join(shell(p), name)]
[06dad0a]225    return l
226
[5b5d6bf]227def copy(src, dst):
[e1346e2]228    src = shell(src)
229    dst = shell(dst)
[5b5d6bf]230    hsrc = host(src)
231    hdst = host(dst)
232    try:
233        shutil.copy(hsrc, hdst)
[f88fcf3]234    except OSError as why:
[5b5d6bf]235        if windows:
236            if WindowsError is not None and isinstance(why, WindowsError):
237                pass
238        else:
[e1346e2]239            raise error.general('copying tree (1): %s -> %s: %s' % (hsrc, hdst, str(why)))
[5b5d6bf]240
[869b8a6]241def copy_tree(src, dst):
[be63b8a]242    trace = False
243
[869b8a6]244    hsrc = host(src)
245    hdst = host(dst)
246
[e1346e2]247    if exists(src):
248        names = listdir(src)
[edf60aa]249    else:
250        names = []
[869b8a6]251
[be63b8a]252    if trace:
[f88fcf3]253        print('path.copy_tree:')
[78c1524]254        print('   src: "%s"' % (src))
255        print('  hsrc: "%s"' % (hsrc))
256        print('   dst: "%s"' % (dst))
257        print('  hdst: "%s"' % (hdst))
[f88fcf3]258        print(' names: %r' % (names))
[be63b8a]259
260    if not os.path.isdir(hdst):
261        if trace:
[f88fcf3]262            print(' mkdir: %s' % (hdst))
[7385feb]263        try:
264            os.makedirs(hdst)
[f88fcf3]265        except OSError as why:
[7385feb]266            raise error.general('copying tree: cannot create target directory %s: %s' % \
267                                (hdst, str(why)))
[869b8a6]268
269    for name in names:
[a84249d]270        srcname = host(os.path.join(hsrc, name))
271        dstname = host(os.path.join(hdst, name))
[869b8a6]272        try:
273            if os.path.islink(srcname):
274                linkto = os.readlink(srcname)
[e1346e2]275                if exists(shell(dstname)):
[85007c3]276                    if os.path.islink(dstname):
277                        dstlinkto = os.readlink(dstname)
278                        if linkto != dstlinkto:
[a84249d]279                            log.warning('copying tree: link does not match: %s -> %s' % \
[85007c3]280                                            (dstname, dstlinkto))
281                            os.remove(dstname)
282                    else:
[d4fa101]283                        log.warning('copying tree: destination is not a link: %s' % \
284                                        (dstname))
[85007c3]285                        os.remove(dstname)
286                else:
287                    os.symlink(linkto, dstname)
[869b8a6]288            elif os.path.isdir(srcname):
289                copy_tree(srcname, dstname)
290            else:
[78c1524]291                shutil.copyfile(host(srcname), host(dstname))
292                shutil.copystat(host(srcname), host(dstname))
[f88fcf3]293        except shutil.Error as err:
[e1346e2]294            raise error.general('copying tree (2): %s -> %s: %s' % \
[be63b8a]295                                (hsrc, hdst, str(err)))
[f88fcf3]296        except EnvironmentError as why:
[e1346e2]297            raise error.general('copying tree (3): %s -> %s: %s' % \
[be63b8a]298                                (srcname, dstname, str(why)))
[869b8a6]299    try:
[be63b8a]300        shutil.copystat(hsrc, hdst)
[f88fcf3]301    except OSError as why:
[edf60aa]302        if windows:
303            if WindowsError is not None and isinstance(why, WindowsError):
304                pass
[869b8a6]305        else:
[e1346e2]306            raise error.general('copying tree (4): %s -> %s: %s' % (hsrc, hdst, str(why)))
[869b8a6]307
[ab8319a]308if __name__ == '__main__':
[f88fcf3]309    print(host('/a/b/c/d-e-f'))
310    print(host('//a/b//c/d-e-f'))
311    print(shell('/w/x/y/z'))
312    print(basename('/as/sd/df/fg/me.txt'))
313    print(dirname('/as/sd/df/fg/me.txt'))
314    print(join('/d', 'g', '/tyty/fgfg'))
[ab8319a]315    windows = True
[f88fcf3]316    print(host('/a/b/c/d-e-f'))
317    print(host('//a/b//c/d-e-f'))
318    print(shell('/w/x/y/z'))
319    print(shell('w:/x/y/z'))
320    print(basename('x:/sd/df/fg/me.txt'))
321    print(dirname('x:/sd/df/fg/me.txt'))
322    print(join('s:/d/e\\f/g', '/h', '/tyty/zxzx', '\\mm\\nn/p'))
Note: See TracBrowser for help on using the repository browser.