1
2
3
4
5
6 """defines interface for all classes that writes L{code_creators.module_t} to file(s)"""
7
8 import os
9 import time
10 import codecs
11 import md5sum_repository
12 from pyplusplus import utils
13 from pyplusplus import _logging_
14 from pyplusplus import code_creators
15 from pyplusplus import code_repository
18 """Base class for all module/code writers.
19
20 All writers should have similar usage::
21
22 w = writer_class(module, file, ...)
23 w.write()
24 """
25 logger = _logging_.loggers.file_writer
26
27 - def __init__(self, extmodule, files_sum_repository=None, encoding='ascii'):
37
38 @property
40 """encoding name used to write generated code to files"""
41 return self.__encoding
42
43 @property
45 """The root of the code creator tree ( code_creators.module_t )"""
46 return self.__extmodule
47
48 @property
50 return self.__files_sum_repository
51
53 """ Main write method. Should be overridden by derived classes. """
54 raise NotImplementedError()
55
56 @staticmethod
58 """creates backup of the file, by renaming it to C{fpath + ~}"""
59 if not os.path.exists( fpath ):
60 return
61 backup_fpath = fpath + '~'
62 if os.path.exists( backup_fpath ):
63 os.remove( backup_fpath )
64 os.rename( fpath, backup_fpath )
65
76 @staticmethod
77 - def write_file( fpath, content, files_sum_repository=None, encoding='ascii' ):
78 """Write a source file.
79
80 This method writes the string content into the specified file.
81 An additional fixed header is written at the top of the file before
82 content.
83
84 @param fpath: File name
85 @type fpath: str
86 @param content: The content of the file
87 @type content: str
88 """
89 fname = os.path.split( fpath )[1]
90 writer_t.logger.debug( 'write code to file "%s" - started' % fpath )
91 start_time = time.clock()
92 fcontent_new = []
93 if os.path.splitext( fpath )[1] == '.py':
94 fcontent_new.append( '# This file has been generated by Py++.' )
95 else:
96 fcontent_new.append( '// This file has been generated by Py++.' )
97 fcontent_new.append( os.linesep * 2 )
98 fcontent_new.append( content )
99 fcontent_new.append( os.linesep )
100 fcontent_new = ''.join( fcontent_new )
101 if not isinstance( fcontent_new, unicode ):
102 fcontent_new = unicode( fcontent_new, encoding )
103
104 new_hash_value = None
105 curr_hash_value = None
106 if files_sum_repository:
107 new_hash_value = files_sum_repository.get_text_value( fcontent_new )
108 curr_hash_value = files_sum_repository.get_file_value( fname )
109 if new_hash_value == curr_hash_value:
110 writer_t.logger.debug( 'file was not changed( hash ) - done( %f seconds )'
111 % ( time.clock() - start_time ) )
112 return
113
114 if None is curr_hash_value and os.path.exists( fpath ):
115
116
117
118 f = codecs.open( fpath, 'rb', encoding )
119 fcontent = f.read()
120 f.close()
121 if fcontent == fcontent_new:
122 writer_t.logger.debug( 'file was not changed( content ) - done( %f seconds )'
123 % ( time.clock() - start_time ) )
124 return
125
126 writer_t.logger.debug( 'file changed or it does not exist' )
127
128 writer_t.create_backup( fpath )
129 f = codecs.open( fpath, 'w+b', encoding )
130 f.write( fcontent_new )
131 f.close()
132 if new_hash_value:
133 files_sum_repository.update_value( fname, new_hash_value )
134 writer_t.logger.info( 'file "%s" - updated( %f seconds )' % ( fname, time.clock() - start_time ) )
135
143
145 self.__exposed_decls_db.save( file_path )
146