[GRASS-SVN] r45764 - in grass/branches/develbranch_6/gui: scripts wxpython wxpython/gui_modules wxpython/xml

svn_grass at osgeo.org svn_grass at osgeo.org
Sat Mar 26 12:09:43 EDT 2011


Author: martinl
Date: 2011-03-26 09:09:43 -0700 (Sat, 26 Mar 2011)
New Revision: 45764

Added:
   grass/branches/develbranch_6/gui/scripts/g.extension.py
Modified:
   grass/branches/develbranch_6/gui/wxpython/gui_modules/ghelp.py
   grass/branches/develbranch_6/gui/wxpython/wxgui.py
   grass/branches/develbranch_6/gui/wxpython/xml/menudata.xml
Log:
wxGUI: backport python g.extepsion script from trunk
       enable install extension window


Copied: grass/branches/develbranch_6/gui/scripts/g.extension.py (from rev 45759, grass/trunk/scripts/g.extension/g.extension.py)
===================================================================
--- grass/branches/develbranch_6/gui/scripts/g.extension.py	                        (rev 0)
+++ grass/branches/develbranch_6/gui/scripts/g.extension.py	2011-03-26 16:09:43 UTC (rev 45764)
@@ -0,0 +1,431 @@
+#!/usr/bin/env python
+
+############################################################################
+#
+# MODULE:       g.extension
+# 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-2011 by Markus Neteler, and the 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 the extensions in local GRASS installation.
+#% description: Downloads, installs extensions from GRASS Addons SVN repository into local GRASS installation or removes installed extensions.
+#% keywords: general
+#% 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
+#% 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 (ignored when flag -s is given)
+#% answer: $GRASS_ADDON_PATH
+#% required: yes
+#%end
+
+#%flag
+#% key: l
+#% description: List available modules in the GRASS Addons SVN repository
+#% guisection: Print
+#%end
+#%flag
+#% key: f
+#% description: List available modules in the GRASS Addons SVN repository including modules description
+#% guisection: Print
+#%end
+#%flag
+#% key: g
+#% description: List available modules in the GRASS Addons SVN repository (shell script style)
+#% guisection: Print
+#%end
+#%flag
+#% key: s
+#% description: Install system-wide (may need system administrator rights)
+#%end
+#%flag
+#% key: d
+#% description: Don't delete downloaded source code when installing new extension
+#%end
+#%flag
+#% key: i
+#% description: Don't install new extension, just compile it
+#%end
+
+import os
+import sys
+import re
+import atexit
+
+import urllib
+
+from grass.script import core as grass
+
+# temp dir
+remove_tmpdir = True
+tmpdir = grass.tempfile()
+grass.try_remove(tmpdir)
+os.mkdir(tmpdir)
+
+def check():
+    for prog in ('svn', 'make', 'install', 'gcc'):
+        if not grass.find_program(prog, ['--help']):
+            grass.fatal(_("%s required. Please install '%s' first.") % (prog, prog))
+    
+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',
+             'gui' : 'gui/wxpython' }
+    
+    if name.has_key(c):
+        return name[c]
+    
+    return c
+
+def list_available_modules(svnurl, full = False, shell = False):
+    mlist = list()
+    grass.message(_('Fetching list of modules from GRASS-Addons SVN (be patient)...'))
+    pattern = re.compile(r'(<li><a href=".+">)(.+)(</a></li>)', re.IGNORECASE)
+    i = 0
+    prefix = ['d', 'db', 'g', 'i', 'm', 'ps',
+              'p', 'r', 'r3', 's', 'v']
+    nprefix = len(prefix)
+    for d in prefix:
+        if shell:
+            grass.percent(i, nprefix, 1)
+            i += 1
+        
+        modclass = expand_module_class_name(d)
+        grass.verbose(_("Checking for '%s' modules...") % modclass)
+        
+        url = '%s/%s' % (svnurl, modclass)
+        grass.debug("url = %s" % url, debug = 2)
+        f = urllib.urlopen(url)
+        if not f:
+            grass.warning(_("Unable to fetch '%s'") % url)
+            continue
+        
+        for line in f.readlines():
+            # list modules
+            sline = pattern.search(line)
+            if not sline:
+                continue
+            name = sline.group(2).rstrip('/')
+            if name.split('.', 1)[0] == d:
+                print_module_desc(name, url, full, shell)
+                mlist.append(name)
+    
+    mlist += list_wxgui_extensions(svnurl, full, shell)
+    
+    if shell:
+        grass.percent(1, 1, 1)
+    
+    return mlist
+
+def list_wxgui_extensions(svnurl, full = False, shell = False, print_module = True):
+    mlist = list()
+    grass.debug('Fetching list of wxGUI extensions from GRASS-Addons SVN (be patient)...')
+    pattern = re.compile(r'(<li><a href=".+">)(.+)(</a></li>)', re.IGNORECASE)
+    grass.verbose(_("Checking for '%s' modules...") % 'gui/wxpython')
+    
+    url = '%s/%s' % (svnurl, 'gui/wxpython')
+    grass.debug("url = %s" % url, debug = 2)
+    f = urllib.urlopen(url)
+    if not f:
+        grass.warning(_("Unable to fetch '%s'") % url)
+        return
+        
+    for line in f.readlines():
+        # list modules
+        sline = pattern.search(line)
+        if not sline:
+            continue
+        name = sline.group(2).rstrip('/')
+        if name not in ('..', 'Makefile'):
+            if print_module:
+                print_module_desc(name, url, full, shell)
+            mlist.append(name)
+    
+    return mlist
+
+def print_module_desc(name, url, full = False, shell = False):
+    if not full and not shell:
+        print name
+        return
+    
+    if shell:
+        print 'name=' + name
+    
+    # check main.c first
+    desc = get_module_desc(url + '/' + name + '/' + name)
+    if not desc:
+        desc = get_module_desc(url + '/' + name + '/main.c', script = False)
+    if not desc:
+        if not shell:
+            print name + '-'
+            return
+    
+    if shell:
+        print 'description=' + desc.get('description', '')
+        print 'keywords=' + ','.join(desc.get('keywords', list()))
+    else:
+        print name + ' - ' + desc.get('description', '')
+    
+def get_module_desc(url, script = True):
+    grass.debug('url=%s' % url)
+    f = urllib.urlopen(url)
+    if script:
+        ret = get_module_script(f)
+    else:
+        ret = get_module_main(f)
+        
+    return ret
+
+def get_module_main(f):
+    if not f:
+        return dict()
+    
+    ret = { 'keyword' : list() }
+    
+    pattern = re.compile(r'(module.*->)(.+)(=)(.*)', re.IGNORECASE)
+    keyword = re.compile(r'(G_add_keyword\()(.+)(\);)', re.IGNORECASE)
+    
+    key   = ''
+    value = ''
+    for line in f.readlines():
+        line = line.strip()
+        find = pattern.search(line)
+        if find:
+            key = find.group(2).strip()
+            line = find.group(4).strip()
+        else:
+            find = keyword.search(line)
+            if find:
+                ret['keyword'].append(find.group(2).replace('"', '').replace('_(', '').replace(')', ''))
+        if key:
+            value += line
+            if line[-2:] == ');':
+                value = value.replace('"', '').replace('_(', '').replace(');', '')
+                if key == 'keywords':
+                    ret[key] = map(lambda x: x.strip(), value.split(','))
+                else:
+                    ret[key] = value
+                
+                key = value = ''
+    
+    return ret
+
+def get_module_script(f):
+    ret = dict()
+    if not f:
+        return ret
+    
+    begin = re.compile(r'#%.*module', re.IGNORECASE)
+    end   = re.compile(r'#%.*end', re.IGNORECASE)
+    mline = None
+    for line in f.readlines():
+        if not mline:
+            mline = begin.search(line)
+        if mline:
+            if end.search(line):
+                break
+            try:
+                key, value = line.split(':', 1)
+                key = key.replace('#%', '').strip()
+                value = value.strip()
+                if key == 'keywords':
+                    ret[key] = map(lambda x: x.strip(), value.split(','))
+                else:
+                    ret[key] = value
+            except ValueError:
+                pass
+    
+    return ret
+
+def cleanup():
+    global tmpdir, remove_tmpdir
+    if remove_tmpdir:
+        grass.try_rmdir(tmpdir)
+    else:
+        grass.info(_("Path to the source code: '%s'") % tmpdir)
+                        
+def install_extension(svnurl, prefix, module, no_install):
+    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)
+    
+    gui_list = list_wxgui_extensions(svnurl, print_module = False)
+
+    if module not in gui_list:
+        classchar = module.split('.', 1)[0]
+        moduleclass = expand_module_class_name(classchar)
+        url = svnurl + '/' + moduleclass + '/' + module
+    else:
+        url = svnurl + '/gui/wxpython/' + module
+        if not flags['s']:
+            grass.fatal(_("Installation of wxGUI extension requires -%s flag") % 's') 
+    
+    grass.message(_("Fetching '%s' from GRASS-Addons SVN (be patient)...") % module)
+    global tmpdir
+    os.chdir(tmpdir)
+    if grass.verbosity() == 0:
+        outdev = open(os.devnull, 'w')
+    else:
+        outdev = sys.stdout
+    
+    if grass.call(['svn', 'checkout',
+                   url], stdout = outdev) != 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.replace(' ', '\ ')],
+                   stdout = outdev) != 0:
+        grass.fatal(_('Compilation failed, sorry. Please check above error messages.'))
+    
+    if no_install or module in gui_list:
+        return
+    
+    grass.message(_("Installing '%s'...") % module)
+    # replace with something better
+    file = os.path.join(prefix, 'test')
+    f = open(file, "w")
+    f.close()
+    os.remove(file)
+ 
+    if not flags['s']:
+        ret = grass.call(['make',
+                          'MODULE_TOPDIR=%s' % gisbase,
+                          'INST_DIR=%s' % prefix,
+                          'install'],
+                         stdout = outdev)
+    else:
+        ret = grass.call(['sudo', 'make',
+                          'MODULE_TOPDIR=%s' % gisbase,
+                          'INST_DIR=%s' % prefix,
+                          'install'],
+                         stdout = outdev)
+    
+    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 os.path.exists(os.path.join(prefix, 'bin', module)):
+        grass.fatal(_("Module '%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 create_dir(path):
+    if os.path.isdir(path):
+        return
+    
+    try:
+        os.makedirs(path)
+    except OSError, e:
+        grass.fatal(_("Unable to create '%s': %s") % (path, e))
+    
+    grass.debug("'%s' created" % path)
+    
+def check_dirs():
+    create_dir(os.path.join(options['prefix'], 'bin'))
+    create_dir(os.path.join(options['prefix'], 'docs', 'html'))
+    create_dir(os.path.join(options['prefix'], 'man', 'man1'))
+
+def main():
+    # check dependecies
+    check()
+    
+    # list available modules
+    if flags['l'] or flags['f'] or flags['g']:
+        list_available_modules(options['svnurl'], full = flags['f'], shell = flags['g'])
+        return 0
+    else:
+        if not options['extension']:
+            grass.fatal(_('You need to define an extension name or use -l'))
+    
+    # define path
+    if flags['s']:
+        options['prefix'] = os.environ['GISBASE']
+    if options['prefix'] == '$GRASS_ADDON_PATH':
+        if not os.environ.has_key('GRASS_ADDON_PATH') or \
+                not os.environ['GRASS_ADDON_PATH']:
+            grass.warning(_("GRASS_ADDON_PATH is not defined, installing to ~/.grass7/addons/"))
+            options['prefix'] = os.path.join(os.environ['HOME'], '.grass7', 'addons')
+    
+    # check dirs
+    check_dirs()
+    
+    if flags['d']:
+        if options['operation'] != 'add':
+            grass.warning(_("Flag 'd' is relevant only to 'operation=add'. Ignoring this flag."))
+        else:
+            global remove_tmpdir
+            remove_tmpdir = False
+    
+    if options['operation'] == 'add':
+        install_extension(options['svnurl'], options['prefix'], options['extension'], flags['i'])
+    else: # remove
+        remove_extension(options['prefix'], options['extension'])
+    
+    return 0
+
+if __name__ == "__main__":
+    options, flags = grass.parser()
+    atexit.register(cleanup)
+    sys.exit(main())

Modified: grass/branches/develbranch_6/gui/wxpython/gui_modules/ghelp.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/ghelp.py	2011-03-26 15:27:58 UTC (rev 45763)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/ghelp.py	2011-03-26 16:09:43 UTC (rev 45764)
@@ -871,7 +871,7 @@
         if not name:
             return
         log = self.parent.GetLogWindow()
-        log.RunCmd(['g.extension', 'extension=' + name,
+        log.RunCmd(['g.extension.py', 'extension=' + name,
                     'svnurl=' + self.repo.GetValue().strip()])
         self.OnCloseWindow(None)
         
@@ -997,7 +997,7 @@
             flags = 'g'
         else:
             flags = 'l'
-        ret = gcmd.RunCommand('g.extension', read = True,
+        ret = gcmd.RunCommand('g.extension.py', read = True,
                               svnurl = url,
                               flags = flags, quiet = True)
         if not ret:

Modified: grass/branches/develbranch_6/gui/wxpython/wxgui.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/wxgui.py	2011-03-26 15:27:58 UTC (rev 45763)
+++ grass/branches/develbranch_6/gui/wxpython/wxgui.py	2011-03-26 16:09:43 UTC (rev 45764)
@@ -89,6 +89,7 @@
 from   gui_modules.debug import Debug
 from   gui_modules.ghelp import MenuTreeWindow
 from   gui_modules.ghelp import AboutWindow
+from   gui_modules.ghelp import InstallExtensionWindow
 from   gui_modules.toolbars import LayerManagerToolbar
 from   icons.icon import Icons
 
@@ -1038,6 +1039,12 @@
         # reset display mode
         os.environ['GRASS_RENDER_IMMEDIATE'] = 'TRUE'
         
+    def OnInstallExtension(self, event):
+        """!Install extension from GRASS Addons SVN repository"""
+        win = InstallExtensionWindow(self, size = (550, 400))
+        win.CentreOnScreen()
+        win.Show()
+
     def OnPreferences(self, event):
         """!General GUI preferences/settings"""
         if not self.dialogs['preferences']:

Modified: grass/branches/develbranch_6/gui/wxpython/xml/menudata.xml
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/xml/menudata.xml	2011-03-26 15:27:58 UTC (rev 45763)
+++ grass/branches/develbranch_6/gui/wxpython/xml/menudata.xml	2011-03-26 16:09:43 UTC (rev 45764)
@@ -842,6 +842,11 @@
 	</menu>
 	<separator />
 	    <menuitem>
+	      <label>Install new extension from add-ons</label>
+	      <help>Install new extension from GRASS AddOns SVN repository.</help>
+	      <handler>OnInstallExtension</handler>
+	    </menuitem>
+	    <menuitem>
 	      <label>Manage add-ons extensions</label>
 	      <help>Tool to maintain GRASS extensions in local GRASS installation.</help>
 	      <keywords>general,extensions</keywords>



More information about the grass-commit mailing list