#!/usr/bin/env python ############################################################################ # # MODULE: g.extension.add # AUTHOR(S): Markus Neteler # Pythonized by Martin Landa # PURPOSE: tool to download and install extensions from GRASS Addons SVN into # local GRASS installation # COPYRIGHT: (C) 2009 by the Markus Neteler, GRASS Development Team # # This program is free software under the GNU General Public # License (>=v2). Read the file COPYING that comes with GRASS # for details. # # TODO: add sudo support where needed (i.e. check first permission to write into # $GISBASE directory) ############################################################################# #%module #% label: Tool to maintain GRASS extensions in local GRASS installation. #% description: Downloads, installs extensions from GRASS Addons SVN repository into local GRASS installation or removes installed extensions. #% keywords: installation #% keywords: extensions #%end #%option #% key: extension #% type: string #% key_desc: name #% description: Name of extension to install/remove #% required: no #%end #%option #% key: operation #% type: string #% key_desc: name #% description: Operation to be performed #% required: no #% options: add,remove #% answer: add #%end #%option #% key: svnurl #% type: string #% key_desc: url #% description: SVN Addons repository URL #% required: yes #% answer: https://svn.osgeo.org/grass/grass-addons/grass7 #%end #%option #% key: prefix #% type: string #% key_desc: path #% description: Prefix where to install extension #% answer: $(HOME)/.grass7/addons #% required: yes #%end #%option #% key: menuitem #% type: string #% key_desc: name #% label: Menu item in wxGUI #% description: Given as string, e.g. 'Imagery;Filter image' #% required: no #%end #%flag #% key: l #% description: List available modules in the GRASS Addons SVN repository #% guisection: Print #%end import os import sys import re import atexit import urllib from grass.script import core as grass # temp dir tmpdir = grass.tempfile() grass.try_remove(tmpdir) os.mkdir(tmpdir) def check(): # check if we have the svn client if not grass.find_program('svn'): grass.fatal(_('svn client required. Please install subversion first.')) def expand_module_class_name(c): name = { 'd' : 'display', 'db' : 'database', 'g' : 'general', 'i' : 'imagery', 'm' : 'misc', 'ps' : 'postscript', 'p' : 'paint', 'r' : 'raster', 'r3' : 'raster3D', 's' : 'sites', 'v' : 'vector' } if name.has_key(c): return name[c] return c def list_available_modules(svnurl): grass.message(_('Fetching list of modules from GRASS-Addons SVN (be patient)...')) pattern = re.compile(r'(
  • )(.+)(
  • )', re.IGNORECASE) for d in ['d', 'db', 'g', 'i', 'ps', 'p', 'r', 'r3', 'v']: modclass = expand_module_class_name(d) url = svnurl + '/' + modclass f = urllib.urlopen(url) if not f: grass.warning(_("Unable to fetch '%s'") % url) continue for line in f.readlines(): sline = pattern.search(line) if sline and sline.group(2).split('.', 1)[0] == d: print sline.group(2).rstrip('/') def cleanup(): global tmpdir grass.try_rmdir(tmpdir) def install_extension(svnurl, prefix, module): gisbase = os.getenv('GISBASE') if not gisbase: grass.fatal(_('$GISBASE not defined')) if grass.find_program(module): grass.warning(_("Extension '%s' already installed. Will be updated...") % module) classchar = module.split('.', 1)[0] moduleclass = expand_module_class_name(classchar) url = svnurl + '/' + moduleclass + '/' + module grass.message(_("Fetching '%s' from GRASS-Addons SVN (be patient)...") % module) global tmpdir os.chdir(tmpdir) if grass.call(['svn', 'checkout', url]) != 0: grass.fatal(_("GRASS Addons '%s' not found in repository") % module) os.chdir(os.path.join(tmpdir, module)) grass.message(_("Compiling '%s'...") % module) if grass.call(['make', 'MODULE_TOPDIR=%s' % gisbase]) != 0: grass.fatal(_('Compilation failed, sorry. Please check above error messages.')) grass.message(_("Installing '%s'...") % module) # can we write ? try: # replace with something better file = os.path.join(prefix, 'test') f = open(file, "w") f.close() os.remove(file) ret = grass.call(['make', 'MODULE_TOPDIR=%s' % gisbase, 'INST_DIR=%s' % prefix, 'install']) except IOError: ret = grass.call(['sudo', 'make', 'MODULE_TOPDIR=%s' % gisbase, 'INST_DIR=%s' % prefix, 'install']) if ret != 0: grass.warning(_('Installation failed, sorry. Please check above error messages.')) else: grass.message(_("Installation of '%s' successfully finished.") % module) def remove_extension(prefix, module): # is module available? if not grass.find_program(module): grass.fatal(_("'%s' not found") % module) for file in [os.path.join(prefix, 'bin', module), os.path.join(prefix, 'scripts', module), os.path.join(prefix, 'docs', 'html', module + '.html')]: if os.path.isfile(file): os.remove(file) grass.message(_("'%s' successfully uninstalled.") % module) def update_menu(menuitem, module, operation): grass.warning(_('Not implemented')) if operation == 'add': pass else: # remove pass def main(): # check dependecies check() # list available modules if flags['l']: list_available_modules(options['svnurl']) return 0 else: if not options['extension']: grass.fatal(_('You need to define an extension name or use -l')) # TODO: check more variable if '$(HOME)' in options['prefix']: options['prefix'] = options['prefix'].replace('$(HOME)', os.environ['HOME']) if not os.path.isdir(options['prefix']): try: os.makedirs(options['prefix']) except OSError, e: grass.fatal(_("Unable to create '%s'\n%s") % (options['prefix'], e)) grass.warning(_("'%s' created") % options['prefix']) if options['operation'] == 'add': install_extension(options['svnurl'], options['prefix'], options['extension']) else: # remove remove_extension(options['prefix'], options['extension']) if options['menuitem']: update_menu(options['menuitem'], options['extension'], options['operation']) return 0 if __name__ == "__main__": options, flags = grass.parser() atexit.register(cleanup) sys.exit(main())