g.extension.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. #!/usr/bin/env python
  2. ############################################################################
  3. #
  4. # MODULE: g.extension.add
  5. # AUTHOR(S): Markus Neteler
  6. # Pythonized by Martin Landa
  7. # PURPOSE: tool to download and install extensions from GRASS Addons SVN into
  8. # local GRASS installation
  9. # COPYRIGHT: (C) 2009 by the Markus Neteler, GRASS Development Team
  10. #
  11. # This program is free software under the GNU General Public
  12. # License (>=v2). Read the file COPYING that comes with GRASS
  13. # for details.
  14. #
  15. # TODO: add sudo support where needed (i.e. check first permission to write into
  16. # $GISBASE directory)
  17. #############################################################################
  18. #%module
  19. #% label: Tool to maintain GRASS extensions in local GRASS installation.
  20. #% description: Downloads, installs extensions from GRASS Addons SVN repository into local GRASS installation or removes installed extensions.
  21. #% keywords: installation, extensions
  22. #%end
  23. #%option
  24. #% key: extension
  25. #% type: string
  26. #% key_desc: name
  27. #% description: Name of extension to install/remove
  28. #% required: no
  29. #%end
  30. #%option
  31. #% key: operation
  32. #% type: string
  33. #% key_desc: name
  34. #% description: Operation to be performed
  35. #% required: no
  36. #% options: add,remove
  37. #% answer: add
  38. #%end
  39. #%option
  40. #% key: svnurl
  41. #% type: string
  42. #% key_desc: url
  43. #% description: SVN Addons repository URL
  44. #% required: yes
  45. #% answer: https://svn.osgeo.org/grass/grass-addons/grass7
  46. #%end
  47. #%option
  48. #% key: prefix
  49. #% type: string
  50. #% key_desc: path
  51. #% description: Prefix where to install extension (default: GISBASE)
  52. #% required: no
  53. #%end
  54. #%option
  55. #% key: menuitem
  56. #% type: string
  57. #% key_desc: name
  58. #% label: Menu item in wxGUI
  59. #% description: Given as string, e.g. 'Imagery;Filter image'
  60. #% required: no
  61. #%end
  62. #%flag
  63. #% key: l
  64. #% description: List available modules in the GRASS Addons SVN repository
  65. #%end
  66. import os
  67. import sys
  68. import re
  69. import atexit
  70. import urllib
  71. from grass.script import core as grass
  72. # temp dir
  73. tmpdir = grass.tempfile()
  74. grass.try_remove(tmpdir)
  75. os.mkdir(tmpdir)
  76. def check():
  77. # check if we have the svn client
  78. if not grass.find_program('svn'):
  79. grass.fatal('svn client required. Please install subversion first.')
  80. def expand_module_class_name(c):
  81. name = { 'd' : 'display',
  82. 'db' : 'database',
  83. 'g' : 'general',
  84. 'i' : 'imagery',
  85. 'm' : 'misc',
  86. 'ps' : 'postscript',
  87. 'p' : 'paint',
  88. 'r' : 'raster',
  89. 'r3' : 'raster3D',
  90. 's' : 'sites',
  91. 'v' : 'vector' }
  92. if name.has_key(c):
  93. return name[c]
  94. return c
  95. def list_available_modules(svnurl):
  96. grass.message('Fetching list of modules from GRASS-Addons SVN (be patient)...')
  97. pattern = re.compile(r'(<li><a href=".+">)(.+)(</a></li>)', re.IGNORECASE)
  98. for d in ['d', 'db', 'g', 'i', 'ps',
  99. 'p', 'r', 'r3', 'v']:
  100. modclass = expand_module_class_name(d)
  101. url = svnurl + '/' + modclass
  102. f = urllib.urlopen(url)
  103. if not f:
  104. grass.warning("Unable to fetch '%s'" % url)
  105. continue
  106. for line in f.readlines():
  107. sline = pattern.search(line)
  108. if sline and sline.group(2).split('.', 1)[0] == d:
  109. print sline.group(2).rstrip('/')
  110. def cleanup():
  111. global tmpdir
  112. grass.try_rmdir(tmpdir)
  113. def install_extension(svnurl, gisbase, module):
  114. if grass.find_program(module):
  115. grass.warning("Extension '%s' already installed. Will be updated..." % module)
  116. classchar = module.split('.', 1)[0]
  117. moduleclass = expand_module_class_name(classchar)
  118. url = svnurl + '/' + moduleclass + '/' + module
  119. grass.message("Fetching '%s' from GRASS-Addons SVN (be patient)..." % module)
  120. global tmpdir
  121. os.chdir(tmpdir)
  122. if grass.call(['svn', 'checkout',
  123. url]) != 0:
  124. grass.fatal("GRASS Addons '%s' not found in repository" % module)
  125. os.chdir(os.path.join(tmpdir, module))
  126. grass.message("Compiling '%s'..." % module)
  127. if grass.call(['make',
  128. 'MODULE_TOPDIR=%s' % gisbase]) != 0:
  129. grass.fatal('Compilation failed, sorry. Please check above error messages')
  130. grass.message("Installing '%s'..." % module)
  131. # can we write ?
  132. try:
  133. # replace with something better
  134. file = os.path.join(gisbase, 'test')
  135. f = open(file, "w")
  136. f.close()
  137. os.remove(file)
  138. ret = grass.call(['make'
  139. 'MODULE_TOPDIR=%s' % gisbase,
  140. 'install'])
  141. except IOError:
  142. ret = grass.call(['sudo', 'make'
  143. 'MODULE_TOPDIR=%s' % gisbase,
  144. 'install'])
  145. if ret != 0:
  146. grass.fatal('Installation failed, sorry. Please check above error messages.')
  147. grass.message("Installation of '%s' successfully finished." % module)
  148. def remove_extension(gisbase, module):
  149. # is module available?
  150. if not grass.find_program(module):
  151. grass.fatal("'%s' not found" % module)
  152. for file in [os.path.join(gisbase, 'bin', module),
  153. os.path.join(gisbase, 'scripts', module),
  154. os.path.join(gisbase, 'docs', 'html', module + '.html')]:
  155. if os.path.isfile(file):
  156. os.remove(file)
  157. grass.message("'%s' successfully uninstalled." % module)
  158. def main():
  159. # check dependecies
  160. check()
  161. # list available modules
  162. if flags['l']:
  163. list_available_modules(options['svnurl'])
  164. return 0
  165. else:
  166. if not options['extension']:
  167. grass.fatal('You need to define an extension name or use -l')
  168. module = options['extension']
  169. if options['prefix']:
  170. gisbase = options['prefix']
  171. else:
  172. gisbase = os.getenv('GISBASE')
  173. if options['operation'] == 'add':
  174. install_extension(options['svnurl'], gisbase, module)
  175. else: # remove
  176. remove_extension(gisbase, module)
  177. return 0
  178. if __name__ == "__main__":
  179. options, flags = grass.parser()
  180. atexit.register(cleanup)
  181. sys.exit(main())