source: branches/numpy/anuga/utilities/system_tools.py @ 6415

Last change on this file since 6415 was 6415, checked in by rwilson, 16 years ago

Added routines to encode/decode arrays of strings (and test).

File size: 9.6 KB
Line 
1"""Implementation of tools to do with system administration made as platform independent as possible.
2
3
4"""
5
6import sys
7import os
8import string
9
10def log_to_file(filename, s, verbose=False):
11    """Log string to file name
12    """
13
14    fid = open(filename, 'a')
15    if verbose: print s
16    fid.write(s + '\n')
17    fid.close()
18
19
20def get_user_name():
21    """Get user name provide by operating system
22    """
23
24    if sys.platform == 'win32':
25        #user = os.getenv('USERPROFILE')
26        user = os.getenv('USERNAME')
27    else:
28        user = os.getenv('LOGNAME')
29
30
31    return user   
32
33def get_host_name():
34    """Get host name provide by operating system
35    """
36
37    if sys.platform == 'win32':
38        host = os.getenv('COMPUTERNAME')
39    else:
40        host = os.uname()[1]
41
42
43    return host   
44
45def get_revision_number():
46    """Get the version number of the SVN
47    NOTE: This requires that the command svn is on the system PATH
48    (simply aliasing svn to the binary will not work)
49    """
50
51    # Create dummy info
52    #info = 'Revision: Version info could not be obtained.'
53    #info += 'A command line version of svn must be availbable '
54    #info += 'on the system PATH, access to the subversion '
55    #info += 'repository is necessary and the output must '
56    #info += 'contain a line starting with "Revision:"'
57   
58
59    #FIXME (Ole): Change this so that svn info is attempted first.
60    # If that fails, try to read a stored file with that same info (this would be created by e.g. the release script). Failing that, throw an exception.
61
62    #FIXME (Ole): Move this and store_version_info to utilities
63
64
65    try:
66        from anuga.stored_version_info import version_info
67    except:
68        msg = 'No version info stored and command "svn" is not '
69        msg += 'recognised on the system PATH.\n\n'
70        msg += 'If ANUGA has been installed from a distribution e.g. as '
71        msg += 'obtained from SourceForge,\n'
72        msg += 'the version info should be '
73        msg += 'available in the automatically generated file '
74        msg += 'stored_version_info.py\n'
75        msg += 'in the anuga root directory.\n'
76        msg += 'If run from a Subversion sandpit, '
77        msg += 'ANUGA will try to obtain the version info '
78        msg += 'by using the command: "svn info".\n'
79        msg += 'In this case, make sure svn is accessible on the system path. '
80        msg += 'Simply aliasing svn to the binary will not work. '
81        msg += 'Good luck!'
82
83        # No file available - try using Subversion
84        try:
85            # The null stuff is so this section fails quitly.
86            # This could cause the svn info command to fail due to
87            # the redirection being bad on some platforms.
88            # If that occurs then change this code.
89            if sys.platform[0:3] == 'win':
90                fid = os.popen('svn info 2> null')
91            else:
92                fid = os.popen('svn info 2>/dev/null')
93       
94        except:
95            raise Exception(msg)
96        else:
97            #print 'Got version from svn'           
98            version_info = fid.read()
99           
100            if version_info == '':
101                raise Exception(msg)   
102    else:
103        pass
104        #print 'Got version from file'
105
106           
107    for line in version_info.split('\n'):
108        if line.startswith('Revision:'):
109            break
110
111    fields = line.split(':')
112    msg = 'Keyword "Revision" was not found anywhere in text: %s' %version_info
113    assert fields[0].startswith('Revision'), msg           
114
115    try:
116        revision_number = int(fields[1])
117    except:
118        msg = 'Revision number must be an integer. I got %s' %fields[1]
119        msg += 'Check that the command svn is on the system path' 
120        raise Exception(msg)               
121       
122    return revision_number
123
124
125def store_version_info(destination_path='.', verbose=False):
126    """Obtain current version from Subversion and store it.
127   
128    Title: store_version_info()
129
130    Author: Ole Nielsen (Ole.Nielsen@ga.gov.au)
131
132    CreationDate: January 2006
133
134    Description:
135        This function obtains current version from Subversion and stores it
136        is a Python file named 'stored_version_info.py' for use with
137        get_version_info()
138
139        If svn is not available on the system PATH, an Exception is thrown
140    """
141
142    # Note (Ole): This function should not be unit tested as it will only
143    # work when running out of the sandpit. End users downloading the
144    # ANUGA distribution would see a failure.
145    #
146    # FIXME: This function should really only be used by developers (
147    # (e.g. for creating new ANUGA releases), so maybe it should move
148    # to somewhere else.
149   
150    import config
151
152    try:
153        fid = os.popen('svn info')
154    except:
155        msg = 'Command "svn" is not recognised on the system PATH'
156        raise Exception(msg)
157    else:   
158        txt = fid.read()
159        fid.close()
160
161
162        # Determine absolute filename
163        if destination_path[-1] != os.sep:
164            destination_path += os.sep
165           
166        filename = destination_path + config.version_filename
167
168        fid = open(filename, 'w')
169
170        docstring = 'Stored version info.\n\n'
171        docstring += 'This file provides the version for distributions '
172        docstring += 'that are not accessing Subversion directly.\n'
173        docstring += 'The file is automatically generated and should not '
174        docstring += 'be modified manually.\n'
175        fid.write('"""%s"""\n\n' %docstring)
176       
177        fid.write('version_info = """\n%s"""' %txt)
178        fid.close()
179
180
181        if verbose is True:
182            print 'Version info stored to %s' %filename
183
184def safe_crc(string):
185    """64 bit safe crc computation.
186
187       See Guido's 64 bit fix at http://bugs.python.org/issue1202           
188    """
189
190    from zlib import crc32
191    import os
192
193    x = crc32(string)
194       
195    if os.name == 'posix' and os.uname()[4] in ['x86_64', 'ia64']:
196        crcval = x - ((x & 0x80000000) << 1)
197    else:
198        crcval = x
199       
200    return crcval
201
202
203def compute_checksum(filename, max_length=2**20):
204    """Compute the CRC32 checksum for specified file
205
206    Optional parameter max_length sets the maximum number
207    of bytes used to limit time used with large files.
208    Default = 2**20 (1MB)
209    """
210
211    fid = open(filename, 'rb') # Use binary for portability
212    crcval = safe_crc(fid.read(max_length))
213    fid.close()
214
215    return crcval
216
217def get_pathname_from_package(package):
218    """Get pathname of given package (provided as string)
219
220    This is useful for reading files residing in the same directory as
221    a particular module. Typically, this is required in unit tests depending
222    on external files.
223
224    The given module must start from a directory on the pythonpath
225    and be importable using the import statement.
226
227    Example
228    path = get_pathname_from_package('anuga.utilities')
229
230    """
231
232    exec('import %s as x' %package)
233
234    path = x.__path__[0]
235   
236    return path
237
238    # Alternative approach that has been used at times
239    #try:
240    #    # When unit test is run from current dir
241    #    p1 = read_polygon('mainland_only.csv')
242    #except:
243    #    # When unit test is run from ANUGA root dir
244    #    from os.path import join, split
245    #    dir, tail = split(__file__)
246    #    path = join(dir, 'mainland_only.csv')
247    #    p1 = read_polygon(path)
248       
249   
250##
251# @brief Split a string into 'clean' fields.
252# @param str The string to process.
253# @param delimiter The delimiter string to split 'line' with.
254# @return A list of 'cleaned' field strings.
255# @note Any fields that were initially zero length will be removed.
256# @note If a field contains '\n' it isn't zero length.
257def clean_line(str, delimiter):
258    """Split string on given delimiter, remove whitespace from each field."""
259
260    return [x.strip() for x in str.strip().split(delimiter) if x != '']
261
262
263################################################################################
264# The following two functions are used to get around a problem with numpy and
265# NetCDF files.  Previously, using Numeric, we could take a list of strings and
266# convert to a Numeric array resulting in this:
267#     Numeric.array(['abc', 'xy']) -> [['a', 'b', 'c'],
268#                                      ['x', 'y', ' ']]
269#
270# However, under numpy we get:
271#     numpy.array(['abc', 'xy']) -> ['abc',
272#                                    'xy']
273#
274# And writing *strings* to a NetCDF file is problematic.
275#
276# The solution is to use these two routines to convert a 1-D list of strings
277# to the 2-D list of chars form and back.  The 2-D form can be written to a
278# NetCDF file as before.
279#
280# The other option, of inverting a list of tag strings into a dictionary with
281# keys being the unique tag strings and the key value a list of indices of where
282# the tag string was in the original list was rejected because:
283#    1. It's a lot of work
284#    2. We'd have to rewite the I/O code a bit (extra variables instead of one)
285#    3. The code below is fast enough in an I/O scenario
286################################################################################
287
288##
289# @brief Convert 1-D list of strings to 2-D list of chars.
290# @param l 1-dimensional list of strings.
291# @return A 2-D list of 'characters' (1 char strings).
292# @note No checking that we supply a 1-D list.
293def string_to_char(l):
294    '''Convert 1-D list of strings to 2-D list of chars.'''
295
296    maxlen = reduce(max, map(len, l))
297    ll = [x.ljust(maxlen) for x in l]
298    result = []
299    for s in ll:
300        result.append([x for x in s])
301    return result
302
303
304##
305# @brief Convert 2-D list of chars to 1-D list of strings.
306# @param ll 2-dimensional list of 'characters' (1 char strings).
307# @return A 1-dimensional list of strings.
308# @note Each string has had right-end spaces removed.
309def char_to_string(ll):
310    '''Convert 2-D list of chars to 1-D list of strings.'''
311
312    return map(string.rstrip, [''.join(x) for x in ll])
313
314
Note: See TracBrowser for help on using the repository browser.