blob: 15530afab422c9aa19bffdfbac3c8882e6fb1cfc [file] [log] [blame]
Matthew Treinish0db53772013-07-26 10:39:35 -04001# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2011 OpenStack Foundation.
4# All Rights Reserved.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17
18
19import contextlib
20import errno
21import os
Matthew Treinishf45528a2013-10-24 20:12:28 +000022import tempfile
Matthew Treinish0db53772013-07-26 10:39:35 -040023
24from tempest.openstack.common import excutils
25from tempest.openstack.common.gettextutils import _ # noqa
26from tempest.openstack.common import log as logging
27
28LOG = logging.getLogger(__name__)
29
30_FILE_CACHE = {}
31
32
33def ensure_tree(path):
34 """Create a directory (and any ancestor directories required)
35
36 :param path: Directory to create
37 """
38 try:
39 os.makedirs(path)
40 except OSError as exc:
41 if exc.errno == errno.EEXIST:
42 if not os.path.isdir(path):
43 raise
44 else:
45 raise
46
47
48def read_cached_file(filename, force_reload=False):
49 """Read from a file if it has been modified.
50
51 :param force_reload: Whether to reload the file.
52 :returns: A tuple with a boolean specifying if the data is fresh
53 or not.
54 """
55 global _FILE_CACHE
56
57 if force_reload and filename in _FILE_CACHE:
58 del _FILE_CACHE[filename]
59
60 reloaded = False
61 mtime = os.path.getmtime(filename)
62 cache_info = _FILE_CACHE.setdefault(filename, {})
63
64 if not cache_info or mtime > cache_info.get('mtime', 0):
65 LOG.debug(_("Reloading cached file %s") % filename)
66 with open(filename) as fap:
67 cache_info['data'] = fap.read()
68 cache_info['mtime'] = mtime
69 reloaded = True
70 return (reloaded, cache_info['data'])
71
72
Matthew Treinishffa94d62013-09-11 18:09:17 +000073def delete_if_exists(path, remove=os.unlink):
Matthew Treinish0db53772013-07-26 10:39:35 -040074 """Delete a file, but ignore file not found error.
75
76 :param path: File to delete
Matthew Treinishffa94d62013-09-11 18:09:17 +000077 :param remove: Optional function to remove passed path
Matthew Treinish0db53772013-07-26 10:39:35 -040078 """
79
80 try:
Matthew Treinishffa94d62013-09-11 18:09:17 +000081 remove(path)
Matthew Treinish0db53772013-07-26 10:39:35 -040082 except OSError as e:
Matthew Treinishffa94d62013-09-11 18:09:17 +000083 if e.errno != errno.ENOENT:
Matthew Treinish0db53772013-07-26 10:39:35 -040084 raise
85
86
87@contextlib.contextmanager
Matthew Treinishffa94d62013-09-11 18:09:17 +000088def remove_path_on_error(path, remove=delete_if_exists):
Matthew Treinish0db53772013-07-26 10:39:35 -040089 """Protect code that wants to operate on PATH atomically.
90 Any exception will cause PATH to be removed.
91
92 :param path: File to work with
Matthew Treinishffa94d62013-09-11 18:09:17 +000093 :param remove: Optional function to remove passed path
Matthew Treinish0db53772013-07-26 10:39:35 -040094 """
Matthew Treinishffa94d62013-09-11 18:09:17 +000095
Matthew Treinish0db53772013-07-26 10:39:35 -040096 try:
97 yield
98 except Exception:
99 with excutils.save_and_reraise_exception():
Matthew Treinishffa94d62013-09-11 18:09:17 +0000100 remove(path)
Matthew Treinish0db53772013-07-26 10:39:35 -0400101
102
103def file_open(*args, **kwargs):
104 """Open file
105
106 see built-in file() documentation for more details
107
108 Note: The reason this is kept in a separate module is to easily
109 be able to provide a stub module that doesn't alter system
110 state at all (for unit tests)
111 """
112 return file(*args, **kwargs)
Matthew Treinishf45528a2013-10-24 20:12:28 +0000113
114
115def write_to_tempfile(content, path=None, suffix='', prefix='tmp'):
116 """Create temporary file or use existing file.
117
118 This util is needed for creating temporary file with
119 specified content, suffix and prefix. If path is not None,
120 it will be used for writing content. If the path doesn't
121 exist it'll be created.
122
123 :param content: content for temporary file.
124 :param path: same as parameter 'dir' for mkstemp
125 :param suffix: same as parameter 'suffix' for mkstemp
126 :param prefix: same as parameter 'prefix' for mkstemp
127
128 For example: it can be used in database tests for creating
129 configuration files.
130 """
131 if path:
132 ensure_tree(path)
133
134 (fd, path) = tempfile.mkstemp(suffix=suffix, dir=path, prefix=prefix)
135 try:
136 os.write(fd, content)
137 finally:
138 os.close(fd)
139 return path