Final version.   ?

Added options: -i (include), -p (object prefix), and fixed -a (append)


Sorry for the many update messages
-cj
#!/usr/local/bin/python
# written by CJ Bell



"""Create dependencies in makefiles for LilyPond scripts

Usage: makedepend_ly [options] files...

Options:
    -h / --help
        Print this message and exit.

    -f, --file=MAKEFILE
        Filename. This allows you to specify an alternate makefile in which
        makedepend_ly can place its output. Specifying ``-'' as the file name
        (i.e., -f-) sends the output to standard output instead of modifying
        an existing file.
    -I, --include=INCLUDEDIR
        Include directory. This option tells makedepend_ly to prepend
        INCLUDEDIR to its list of directories to search when it encounters an
        \include directive. By default, makedepend_ly only searches the
        standard include directories.
    -Y, --onlyinclude=INCLUDEDIR
        Replace all of the standard include directories with the single
        specified include directory. 
    -o, -objsuffix=SUFFIX
        Object file suffix. Default is '.ps'.
    -p, -objprefix=SUFFIX
        Object file prefix. The prefix is prepended to the name of the object
        file. This is usually used to designate a different directory for the
        object file. The default is the empty string. 
    -i, -include=FILE
        Process FILE as input, and include all the resulting output before
        processing the regular input file. This has the same affect as if the
        specified file is an include statement that appears before the very
        first line of the regular input file. 
    -a, --append
        Append the dependencies to the end of the file instead of replacing
        them.
    -s, --start=STRING
        Starting string delimiter. This option permits you to specify a
        different string for makedepend_ly to look for in the makefile.
"""


import tempfile
import os
import shutil
import sys
import getopt
import fileinput
import re


# Pattern used to parse for a lilypond include
inclfn = re.compile(r"[ \t]*\\include[ 
\t]+\"(?P<filename>(?:(?:\\[\"])|[^\"])*)\"")


ntPath = 'C:/Program Files/LilyPond/usr/share/lilypond/current/ly'
posixPath = '/usr/share/lilypond/current/ly'

includePaths = []
standardIncludes = []

if os.path.exists(ntPath):
  standardIncludes.append(ntPath)
if os.path.exists(posixPath):
  standardIncludes.append(posixPath)

if 'relpath' not in dir(os.path):
  os.path.relpath = lambda p: p



##############################################################################
def main(argv):                         
  global includePaths
  linkspaces = False
  append = False
  starting_str = '# DO NOT DELETE THIS LINE -- makedepend_ly depends on it.'
  objsuffix = '.ps'
  objprefix = ''
  autoIncludes = set()

  if os.path.exists('makefile'):
      outputFile = 'makefile'
  else:
      outputFile = 'Makefile'
  

  try:                                
      longopts = 
['help','file=','include=','onlyinclude=','linkspaces=','append','start=','objsuffix=','objprefix=','include=']
      opts, files= getopt.getopt(argv, 'hf:I:Y:as:o:p:i:', longopts) 
  except getopt.GetoptError:           
      usage()                          
      sys.exit(2)

  for opt, arg in opts:
      if opt in ("-h", "--help"):
          usage()
          sys.exit()
      if opt in ('-f','--file'):
          outputFile = arg
      if opt in ('-I','--include'):
          if not os.path.exists(arg):
              print "Included directory " + arg + " doesn't exist"
              sys.exit(1)
          includePaths.append(arg)
      if opt in ('-Y','--onlyinclude'):
          if not os.path.exists(arg):
              print "Included directory " + arg + " doesn't exist"
              sys.exit(1)
          standardInclude = [arg]
      if opt == '--linkspaces':
          linkspaces = True
          ns_link_dir = arg
      if opt in ('-a','--append'):
          append = True
      if opt in ('-s','--start'):
          starting_string = arg
      if opt in ('-o','--objsuffix'):
          objsuffix = arg
      if opt in ('-p','--objprefix'):
          objprefix = arg
      if opt in ('-i','--include'):
          autoIncludes.add(os.path.abspath('parts.ly'))

  includePaths+= standardIncludes

  objfiles = set()
  for file in files:
    objfiles.add(os.path.join(os.path.abspath(file)))
      

  # current directory
  cd = './'    

  depends = dict()

  for objfile in objfiles:
      depends[objfile] = set()
      checked = set()
      toCheck = set([objfile])|autoIncludes

      while toCheck:
          files = toCheck - checked
          toCheck = set()

          for file in files:
              included = parseFile(file, includePaths)
              depends[objfile]|= included
              toCheck |= included
              checked.add(file)


  # Make links for each filename with a space so it can be referred-to in the
  # makefile
  if linkspaces:
      try:
          os.mkdir(ns_link_dir)
      except EnvironmentError, err:
          if err.errno != 17:
              pass

      new_keys = []
      for file in depends.keys():
          new_keys.append(linkNoSpace(file, ns_link_dir))

      new_values = [];
      for deps in depends.values():
          new_deps = []
          for file in deps:
              new_deps.append(linkNoSpace(file, ns_link_dir))
          new_values.append(new_deps)

      depends = dict(zip(new_keys, new_values))

  # Output dependencies
  old_f = None
  if outputFile == '-':
      f = sys.stdout
  else:
      try:
          old_f = open(outputFile, 'r')
      except IOError, err:
          if err.errno != 2:
              pass
          f = open(outputFile, 'w')
          f.write(starting_str + '\n')
      else:
          if not append:
              # Copy the file up until the starting deliminator
              f = tempfile.TemporaryFile()
              startFound = False
              for line in old_f:
                  f.write(line)
                  if line == starting_str+'\n':
                      startFound = True
                      break
              if not startFound:
                  f.write('\n' + starting_str + '\n')
          else:
              old_f.close()
              old_f = None
              f = open(outputFile, 'a')

  if not f:
      print "Cannot open " + outputFile + " for writing"
      sys.exit()

  for file, deps in depends.items():
      (filebase,_) = os.path.splitext(os.path.relpath(file))

      target = objprefix + filebase + objsuffix
      f.write(target + ': ' + os.path.relpath(file)  + '\n')
      for dep in deps:
          f.write(target + ': ' + os.path.relpath(dep) + '\n')
      f.write('\n')

  if old_f:
      old_f.close()
      old_f = open(outputFile, 'w')
      f.seek(0)
      shutil.copyfileobj(f,old_f)      
      old_f.close()

  if f != sys.stdout:
      f.close()



# End main        
##############################################################################



##############################################################################
def usage():
    print __doc__
# End usage
##############################################################################



##############################################################################
def linkNoSpace(file, basedir):
    if ' ' not in file:
        return file

    new_filename = os.path.basename(file)
    if os.path.exists(os.path.join(basedir,new_filename)):
        if os.readlink(os.path.join(basedir,new_filename)) == file:
            return os.path.join(basedir,new_filename)
            
        n = 2
        while os.path.exists(os.path.join(basedir,str(n) + '.' + new_filename)):
            n+= 1
        new_filename = str(n) + '.' + new_filename

    os.symlink(file, os.path.join(basedir,new_filename))
    return os.path.join(basedir,new_filename)
# End linkNoSpace
##############################################################################



##############################################################################
def parseFile(file, includePaths):
  includes = set()
  cd = os.path.dirname(file)
  for line in fileinput.input(file):
    try:
      f = parseLine(line, cd, includePaths)
    except EnvironmentError, err:
      print "In " + os.path.relpath(file) + ", " + err.strerror + ": " + 
err.filename
    else:
      if f is not None:
        includes.add(f)

  return includes
# End parseFile
##############################################################################  
  



##############################################################################
def parseLine(line, cd, includePaths):
  global inclfn

  match = inclfn.match(line)
  if match is None:
    return None

  file = match.group('filename')

  # cheack each include path, then the file's directory
  for incl in includePaths+[cd]:
    f = os.path.join(incl,file)
    if os.path.exists(os.path.join(incl,file)):
      return f

  # included file can't be found
  raise EnvironmentError(-1,"cannot find included file", file)
# End parseLine
##############################################################################




if __name__ == "__main__":
    main(sys.argv[1:])



_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
http://lists.gnu.org/mailman/listinfo/lilypond-user

Reply via email to