source: rtems-tools/rtemstoolkit/path.py @ 3618a62

Last change on this file since 3618a62 was bf58911, checked in by Chris Johns <chrisj@…>, on Oct 24, 2017 at 10:35:21 AM

tester: Refactor to use INI format files for BSP configurations.

  • Add support for user condfigurations files with the --user-config.
  • Add support for a $HOME/.rtemstesterrc for a user configuration.

Closes #3204.

  • Property mode set to 100644
File size: 7.8 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2010-2016 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
37from __future__ import print_function
38
39import glob
40import os
41import shutil
42import string
43
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#
48try:
49    from . import error
50    from . import log
51except (ValueError, SystemError):
52    import error
53    import log
54
55windows = os.name == 'nt'
56
57def 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
68def 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
76def basename(path):
77    return shell(os.path.basename(path))
78
79def dirname(path):
80    return shell(os.path.dirname(path))
81
82def 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
91def abspath(path):
92    return shell(os.path.abspath(host(path)))
93
94def splitext(path):
95    root, ext = os.path.splitext(host(path))
96    return shell(root), ext
97
98def 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
106def isdir(path):
107    return os.path.isdir(host(path))
108
109def isfile(path):
110    return os.path.isfile(host(path))
111
112def isabspath(path):
113    return path[0] == '/'
114
115def iswritable(path):
116    return os.access(host(path), os.W_OK)
117
118def 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
126def 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))
135            except IOError:
136                raise error.general('cannot make directory: %s' % (path))
137            except OSError:
138                raise error.general('cannot make directory: %s' % (path))
139            except WindowsError:
140                raise error.general('cannot make directory: %s' % (path))
141        else:
142            try:
143                os.makedirs(host(path))
144            except IOError:
145                raise error.general('cannot make directory: %s' % (path))
146            except OSError:
147                raise error.general('cannot make directory: %s' % (path))
148
149def removeall(path):
150
151    def _onerror(function, path, excinfo):
152        print('removeall error: (%s) %s' % (excinfo, path))
153
154    path = host(path)
155    shutil.rmtree(path, onerror = _onerror)
156
157def expand(name, paths):
158    l = []
159    for p in paths:
160        l += [join(p, name)]
161    return l
162
163def expanduser(path):
164    path = host(path)
165    path = os.path.expanduser(path)
166    return shell(path)
167
168def 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
190def 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)
225        except shutil.Error as err:
226            raise error.general('copying tree: %s -> %s: %s' % (src, dst, str(err)))
227        except EnvironmentError as why:
228            raise error.general('copying tree: %s -> %s: %s' % (srcname, dstname, str(why)))
229    try:
230        shutil.copystat(src, dst)
231    except OSError as why:
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
239if __name__ == '__main__':
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'))
246    windows = True
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'))
Note: See TracBrowser for help on using the repository browser.