[GRASS-SVN] r49720 - grass/branches/develbranch_6/gui/scripts

svn_grass at osgeo.org svn_grass at osgeo.org
Tue Dec 13 13:11:33 EST 2011


Author: martinl
Date: 2011-12-13 10:11:33 -0800 (Tue, 13 Dec 2011)
New Revision: 49720

Modified:
   grass/branches/develbranch_6/gui/scripts/g.extension.py
Log:
g.extensions.py: sync with trunk (store local xml files + list installed extensions) - r49716


Modified: grass/branches/develbranch_6/gui/scripts/g.extension.py
===================================================================
--- grass/branches/develbranch_6/gui/scripts/g.extension.py	2011-12-13 18:10:58 UTC (rev 49719)
+++ grass/branches/develbranch_6/gui/scripts/g.extension.py	2011-12-13 18:11:33 UTC (rev 49720)
@@ -56,20 +56,25 @@
 
 #%flag
 #% key: l
-#% description: List available modules in the GRASS Addons SVN repository
+#% description: List available extensions in the GRASS Addons SVN repository
 #% guisection: Print
 #%end
 #%flag
 #% key: c
-#% description: List available modules in the GRASS Addons SVN repository including module description
+#% description: List available extensions in the GRASS Addons SVN repository including module description
 #% guisection: Print
 #%end
 #%flag
 #% key: g
-#% description: List available modules in the GRASS Addons SVN repository (shell script style)
+#% description: List available extensions in the GRASS Addons SVN repository (shell script style)
 #% guisection: Print
 #%end
 #%flag
+#% key: a
+#% description: List locally installed extension
+#% guisection: Print
+#%end
+#%flag
 #% key: s
 #% description: Install system-wide (may need system administrator rights)
 #%end
@@ -135,8 +140,35 @@
     
     return c
 
-# list modules (read XML file from grass.osgeo.org/addons)
-def list_available_modules():
+
+# list installed extensions
+def get_installed_extensions(force = False):
+    fXML = os.path.join(options['prefix'], 'modules.xml')
+    if not os.path.exists(fXML):
+        if force:
+            write_xml_modules(fXML)
+        else:
+            grass.warning(_("No metadata file available"))
+        return []
+    
+    # read XML file
+    fo = open(fXML, 'r')
+    try:
+        tree = etree.fromstring(fo.read())
+    except:
+        os.remove(fXML)
+        write_xml_modules(fXML)
+        return []
+    fo.close()
+    
+    ret = list()
+    for tnode in tree.findall('task'):
+        ret.append(tnode.get('name'))
+    
+    return ret
+
+# list extensions (read XML file from grass.osgeo.org/addons)
+def list_available_extensions():
     mlist = list()
 
     # try to download XML metadata file first
@@ -163,14 +195,14 @@
             else:
                 print name
     except HTTPError:
-        return list_available_modules_svn()
+        return list_available_extensions_svn()
     
     return mlist
 
-# list modules (scan SVN repo)
-def list_available_modules_svn():
+# list extensions (scan SVN repo)
+def list_available_extensions_svn():
     mlist = list()
-    grass.message(_('Fetching list of modules from GRASS-Addons SVN (be patient)...'))
+    grass.message(_('Fetching list of extensions from GRASS-Addons SVN (be patient)...'))
     pattern = re.compile(r'(<li><a href=".+">)(.+)(</a></li>)', re.IGNORECASE)
 
     if flags['c']:
@@ -194,7 +226,7 @@
             continue
         
         for line in f.readlines():
-            # list modules
+            # list extensions
             sline = pattern.search(line)
             if not sline:
                 continue
@@ -222,7 +254,7 @@
         return
         
     for line in f.readlines():
-        # list modules
+        # list extensions
         sline = pattern.search(line)
         if not sline:
             continue
@@ -241,6 +273,147 @@
         grass.message(_("Path to the source code:"))
         sys.stderr.write('%s\n' % os.path.join(tmpdir, options['extension']))
 
+# write out meta-file
+def write_xml_modules(name, tree = None):
+    fo = open(name, 'w')
+    version = grass.version()['version'].split('.')[0]
+    fo.write('<?xml version="1.0" encoding="UTF-8"?>\n')
+    fo.write('<!DOCTYPE task SYSTEM "grass-addons.dtd">\n')
+    fo.write('<addons version="%s">\n' % version)
+    
+    if tree is not None:
+        for tnode in tree.findall('task'):
+            indent = 4
+            fo.write('%s<task name="%s">\n' % (' ' * indent, tnode.get('name')))
+            indent += 4
+            fo.write('%s<description>%s</description>\n' % \
+                         (' ' * indent, tnode.find('description').text))
+            fo.write('%s<keywords>%s</keywords>\n' % \
+                         (' ' * indent, tnode.find('keywords').text))
+            bnode = tnode.find('binary')
+            if bnode is not None:
+                fo.write('%s<binary>\n' % (' ' * indent))
+                indent += 4
+                for fnode in bnode.findall('file'):
+                    fpath = fnode.text.split(os.path.sep)
+                    if not flags['s']: # tidy citizen hacks
+                        if fpath[0] in ('bin', 'scripts'):
+                            del fpath[0]
+                        if fpath[0] == 'man':
+                            fpath.insert(0, 'docs')
+                    
+                    fo.write('%s<file>%s</file>\n' % \
+                                 (' ' * indent, os.path.join(options['prefix'],
+                                                             os.path.sep.join(fpath))))
+                indent -= 4 
+                fo.write('%s</binary>\n' % (' ' * indent))
+            libgisRev = grass.version()['libgis_revision']
+            fo.write('%s<libgis revision="%s" />\n' % \
+                         (' ' * indent, libgisRev))
+            indent -= 4
+            fo.write('%s</task>\n' % (' ' * indent))
+    
+    fo.write('</addons>\n')
+    fo.close()
+    
+# update local meta-file when installing new extension
+def install_extension_xml():
+    # read metadata from remote server
+    url = "http://grass.osgeo.org/addons/grass%s.xml" % grass.version()['version'].split('.')[0]
+    data = None
+    try:
+        f = urlopen(url)
+        tree = etree.fromstring(f.read())
+        for mnode in tree.findall('task'):
+            name = mnode.get('name')
+            if name != options['extension']:
+                continue
+            
+            fList = list()
+            bnode = mnode.find('binary')
+            windows = sys.platform == 'win32'
+            if bnode is not None:
+                for fnode in bnode.findall('file'):
+                    path = fnode.text.split('/')
+                    if windows:
+                        if path[0] == 'bin':
+                            path[-1] += '.exe'
+                        if path[0] == 'scripts':
+                            path[-1] += '.py'
+                    fList.append(os.path.sep.join(path))
+            
+            desc = mnode.find('description').text
+            if not desc:
+                desc = ''
+            keyw = mnode.find('keywords').text
+            if not keyw:
+                keyw = ''
+            
+            data = { 'name'  : name,
+                     'desc'  : desc,
+                     'keyw'  : keyw,
+                     'files' : fList,
+                     }
+    except HTTPError:
+        grass.error(_("Unable to read metadata file from the remote server"))
+    
+    if not data:
+        grass.warning(_("No metadata available"))
+        return
+
+    fXML = os.path.join(options['prefix'], 'modules.xml')
+    # create an empty file if not exists
+    if not os.path.exists(fXML):
+        write_xml_modules(fXML)
+    
+    # read XML file
+    fo = open(fXML, 'r')
+    tree = etree.fromstring(fo.read())
+    fo.close()
+    
+    # update tree
+    tnode = None
+    for node in tree.findall('task'):
+        if node.get('name') == options['extension']:
+            tnode = node
+            break
+    
+    if tnode is not None:
+        # update existing node
+        dnode = tnode.find('description')
+        if dnode is not None:
+            dnode.text = data['desc']
+        knode = tnode.find('keywords')
+        if knode is not None:
+            knode.text = data['keyw']
+        bnode = tnode.find('binary')
+        if bnode is not None:
+            tnode.remove(bnode)
+        bnode = etree.Element('binary')
+        for f in data['files']:
+            fnode = etree.Element('file')
+            fnode.text = f
+            bnode.append(fnode)
+        tnode.append(bnode)
+    else:
+        # create new node for task
+        tnode = etree.Element('task', attrib = { 'name' : data['name'] })
+        dnode = etree.Element('description')
+        dnode.text = data['desc']
+        tnode.append(dnode)
+        knode = etree.Element('keywords')
+        knode.text = data['keyw']
+        tnode.append(knode)
+        bnode = etree.Element('binary')
+        for f in data['files']:
+            fnode = etree.Element('file')
+            fnode.text = f
+            bnode.append(fnode)
+        tnode.append(bnode)
+        tree.append(tnode)
+    
+    write_xml_modules(fXML, tree)
+
 # install extension on MS Windows
 def install_extension_win():
     ### TODO: do not use hardcoded url
@@ -280,8 +453,8 @@
     if not gisbase:
         grass.fatal(_('$GISBASE not defined'))
     
-    if grass.find_program(options['extension'], ['--help']):
-        grass.warning(_("Extension <%s> already installed. Will be updated...") % options['extension'])
+    if options['extension'] in get_installed_extensions(force = True):
+        grass.warning(_("Extension <%s> already installed. Re-installing...") % options['extension'])
     
     if sys.platform == "win32":
         ret = install_extension_win()
@@ -291,6 +464,8 @@
     if ret != 0:
         grass.warning(_('Installation failed, sorry. Please check above error messages.'))
     else:
+        grass.message(_("Updating metadata file..."))
+        install_extension_xml()
         grass.message(_("Installation of <%s> successfully finished") % options['extension'])
     
     # cleanup build cruft
@@ -420,41 +595,56 @@
     # if empty, rmdir bin, etc, man, scripts
     for d in ('bin', 'etc', os.path.join('man', 'man1'), 'man', 'scripts'):
         remove_empty_dir(os.path.join(options['prefix'], d))
+
+# update local meta-file when removing existing extension
+def remove_extension_xml():
+    fXML = os.path.join(options['prefix'], 'modules.xml')
+    if not os.path.exists(fXML):
+        return
     
+    # read XML file
+    fo = open(fXML, 'r')
+    tree = etree.fromstring(fo.read())
+    fo.close()
+
+    tnode = None
+    for node in tree.findall('task'):
+        if node.get('name') == options['extension']:
+            tnode = node
+            break
+
+    if tnode is not None:
+        tree.remove(tnode)
+        
+    write_xml_modules(fXML, tree)
+    
 # remove existing extension (reading XML file)
 def remove_extension(force = False):
-    # try to download XML metadata file first
-    url = "http://grass.osgeo.org/addons/grass%s.xml" % grass.version()['version'].split('.')[0]
+    # try to read XML metadata file first
+    fXML = os.path.join(options['prefix'], 'modules.xml')
     name = options['extension']
+    if name not in get_installed_extensions():
+        grass.warning(_("Extension <%s> not found") % name)
+    
     if force:
         grass.verbose(_("List of removed files:"))
     else:
         grass.info(_("Files to be removed (use flag 'f' to force removal):"))
     
-    try:
-        f = urlopen(url)
+    if os.path.exists(fXML):
+        f = open(fXML, 'r')
         tree = etree.fromstring(f.read())
         flist = []
         for task in tree.findall('task'):
             if name == task.get('name', default = '') and \
                     task.find('binary') is not None:
                 for f in task.find('binary').findall('file'):
-                    fname = f.text
-                    if fname:
-                        fpath = fname.split('/')
-                        if sys.platform == 'win32':
-                            if fpath[0] == 'bin':
-                                fpath[-1] += '.exe'
-                            if fpath[0] == 'scripts':
-                                fpath[-1] += '.py'
-                        
-                        flist.append(fpath)
+                    flist.append(f.text)
         
         if flist:
             removed = False
             err = list()
-            for f in flist:
-                fpath = os.path.join(options['prefix'], os.path.sep.join(f))
+            for fpath in flist:
                 try:
                     if force:
                         grass.verbose(fpath)
@@ -472,13 +662,15 @@
                     grass.error(e)
         else:
             remove_extension_std(force)
-    except HTTPError:
+    else:
         remove_extension_std(force)
 
     if force:
+        grass.message(_("Updating metadata file..."))
+        remove_extension_xml()
         grass.message(_("Extension <%s> successfully uninstalled.") % options['extension'])
     else:
-        grass.warning(_("Extension <%s> not removed. "
+        grass.warning(_("Extension <%s> not removed.\n"
                         "Re-run '%s' with 'f' flag to force removal") % (options['extension'], 'g.extension'))
     
 # remove exising extension (using standard files layout)
@@ -537,14 +729,6 @@
     if sys.platform != "win32":
         check_progs()
     
-    # list available modules
-    if flags['l'] or flags['c'] or flags['g']:
-        list_available_modules()
-        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']
@@ -563,6 +747,18 @@
                 grass.warning(_("GRASS_ADDON_PATH has more items, using first defined - '%s'") % path_list[0])
             options['prefix'] = path_list[0]
     
+    # list available modules
+    if flags['l'] or flags['c'] or flags['g']:
+        list_available_modules()
+        return 0
+    elif flags['a']:
+        grass.message(_("List of installed extensions:"))
+        print os.linesep.join(get_installed_extensions())
+        return 0
+    else:
+        if not options['extension']:
+            grass.fatal(_('You need to define an extension name or use -l'))
+
     if flags['d']:
         if options['operation'] != 'add':
             grass.warning(_("Flag 'd' is relevant only to 'operation=add'. Ignoring this flag."))



More information about the grass-commit mailing list