6.13.2.5. Complex Disk File Sink

This class provides more advanced facilities than the simple disk file. Output is written to a temporary file until the driver is closed. At that point, the temporary file is compared line by line with the target file, and if the files differ, the temporary file is copied onto the target, and then, in either case the temporary deleted.

This mechanism has several purposes. First, it is used to prevent 'make' systems recompiling unchanged code files. Second, it is used so that the output of a previous run can be read back in while the current run is generating a new copy. Finally, the comparisons on all these files can be used to determine if the literate programming process has converged to a stable point or may require another pass.

Please note that some care is required to ensure convergence is possible. Note also that when line numbers are generated, a single change to the source file will cause comparisons to fail for all files with sections defined after that point, often causing an apparently redundant rebuild. This is not alsways the case, for example, in C, the assert macro reports line numbers at run time, and the rebuild is necessary. It may be useful to turn off line number generation for files once they have compiled successfully (until the production build).

Finally, note that if you put the time into an output file, it is likely to be different each run!

Start python section to interscript/drivers/sinks/bufdisk.py[1 /1 ]
     1: #line 233 "sink_drivers.ipk"
     2: import string
     3: from interscript.drivers.sinks.base import sink_base
     4: from interscript.drivers.sinks import sink_open_error
     5: 
     6: class named_file_sink(sink_base):
     7:   def __init__(self,pass_frame,input_filename, prefix='', eol='\n'):
     8:     self.pass_frame = pass_frame
     9:     self.process = pass_frame.process
    10:     self.site = self.process.site
    11:     self.platform = self.site.platform
    12:     if 'sinks' in self.process.trace:
    13:       self.process.acquire_object(self,'NAMED FILE SINK '+input_filename)
    14:     self.eol = eol
    15: 
    16:     # compute absolute pathname, and create directories if necessary
    17:     # we don't use posixpath because we're enforcing an _interscript_
    18:     # pathname convention here
    19:     pathlist = string.split(input_filename,'/')
    20:     self.basename = pathlist[-1]
    21:     pathname = self.platform.mk_dir(prefix, pathlist)
    22: 
    23:     if self.platform.file_exists(pathname):
    24:       self.tmp_filename = self.platform.tempfile.mktemp()
    25:       if 'sinks' in self.process.trace:
    26:         print 'Generating temporary',self.tmp_filename,'for',input_filename
    27:       try:
    28:         file =self.platform.open(self.tmp_filename,'w')
    29:         self.pass_frame.fdict[input_filename]='temporary'
    30:       except:
    31:         raise sink_open_error, self.tmp_filename
    32:       sink_base.__init__(self, filename = pathname, name = input_filename, file = file )
    33:       if pass_frame: self.pass_frame.flist.append(input_filename)
    34:     else:
    35:       if 'sinks' in self.process.trace:
    36:         print 'Generating original',input_filename
    37:       try:
    38:         file = self.platform.open(pathname,'w')
    39:         if pass_frame: self.pass_frame.fdict[input_filename]='original'
    40:       except:
    41:         raise sink_open_error,pathname
    42:       sink_base.__init__(self, filename = pathname, name = input_filename, file = file)
    43:       if pass_frame: self.pass_frame.flist.append(input_filename)
    44: 
    45:   def __del__(self):
    46:     pass_frame = self.__dict__.get('pass_frame',None)
    47:     if 'sinks' in self.process.trace:
    48:       print 'closing', self.name
    49:     self.file.close()
    50:     if hasattr(self,'tmp_filename'):
    51:       if self.process.update_files:
    52:         original_file = self.platform.open(self.filename,'r')
    53:         original_lines = original_file.readlines()
    54:         original_file.close()
    55: 
    56:         new_file = self.platform.open(self.tmp_filename,'r')
    57:         new_lines = new_file.readlines()
    58:         new_file.close()
    59: 
    60:         if not original_lines == new_lines:
    61:           if 'changes' in self.process.trace:
    62:             print 'File',self.filename,'is CHANGED'
    63:           if pass_frame:
    64:             self.pass_frame.fdict[self.name]='changed'
    65:           file = self.platform.open(self.filename,'w')
    66:           file.writelines(new_lines)
    67:           file.close()
    68:         else:
    69:           if 'changes' in self.process.trace:
    70:             print 'File',self.filename,'is unchanged'
    71:           if pass_frame: self.pass_frame.fdict[self.name]='unchanged'
    72:       else:
    73:         print '*** System error inhibiting file update for',self.filename,'***'
    74:         if pass_frame: self.pass_frame.fdict[self.name]='cancelled'
    75:       self.platform.os.remove(self.tmp_filename)
    76:     else:
    77:       if 'changes' in self.process.trace:
    78:         print 'File',self.filename,'is NEW'
    79:     if hasattr(self,'process') and 'sinks' in self.process.trace:
    80:       self.process.release_object(self)
    81: 
    82:   def raw_write(self,line): self.file.write(line)
    83:   def raw_eol(self): self.raw_write(self.eol)
    84: 
End python section to interscript/drivers/sinks/bufdisk.py[1]