Permalink
Browse files

Better metadata.txt handling. Experimental flag is now read from meta…

…data.
  • Loading branch information...
1 parent 6bd178f commit 8da8c29eea3f2952afe508aafe1250847d3a513a @elpaso elpaso committed Oct 5, 2012
@@ -44,13 +44,7 @@ The validation takes place in the PluginVersions forms, at loading time, the com
* file size <= `PLUGIN_MAX_UPLOAD_SIZE`
* zip contains `__init__.py` in first level dir
-* `__init__.py` must contain valid metadata:
- * `name`
- * `description`
- * `version`
- * `qgisMinimumVersion`
- * `email`
- * `author`
+* `__init__.py` must contain valid metadata
* `version` must be unique whithin a plugin
@@ -74,56 +68,11 @@ Example from the `HelloWorld` plugin compressed zip file::
--------- -------
3168 5 files
+Metadata
+========
+TODO: add a link to the metadata.rst file.
-Metadata
---------
-
-Plugins mandatory metadata [#f1]_ are read from both the old `__init__.py` functions format
-and (if present) the new `metadata.txt` file.
-
-To avoid direct execution of python code (which would be a security issue), metadata are read from the `__init__.py` file with a simple regular expression parser which extracts the string values returned by the functions inside the `__init__.py` file, this means that if the functions do not return strings (enclosed in single or double quotes), the metadata entry for that function will not be extracted and if the metadata is mandatory the plugin will be considered invalid.
-
-The new `metadata.txt` file can contain other optional metadata which are read when the package is uploaded and are automatically imported.
-
-Example configuration file::
-
- ; the next section is mandatory
- [general]
- name=HelloWorld
- qgisMinimumVersion=1.8
- description=This is a plugin for greeting the
- (going multiline) world
- version=version 1.2
- author=Alessandro Pasotti
- email=email@email.com
- ; end of mandatory metadata
-
- ; start of optional metadata
- changelog=this is a very
- very
- very
- very
- very
- very long multiline changelog
-
- ; tags are in comma separated value format, spaces are allowed
- tags=wkt,raster,hello world
-
- ; these metadata can be empty
- ; in a future version of the web application it will
- ; be probably possible to create a project on redmine
- ; if they are not filled
- homepage=http://www.itopen.it
- tracker=http://bugs.itopen.it
- repository=http://www.itopen.it/repo
- icon=icon.png
-
- ; experimental flag
- experimental=True
-
- ; deprecated flag (applies to the whole plugin and not only to the uploaded version)
- deprecated=False
Configuration
=============
@@ -0,0 +1,64 @@
+
+Metadata
+--------
+
+Plugins mandatory metadata [#f1]_ are read from both the old `__init__.py` functions format
+and (if present) the new `metadata.txt` file.
+
+Valid metadata for the `__init__` file are:
+ * `name`
+ * `description`
+ * `version`
+ * `qgisMinimumVersion`
+ * `email`
+ * `author`
+ * `experimental`
+
+To avoid direct execution of python code (which would be a security issue), metadata are read from the `__init__.py` file with a simple regular expression parser which extracts the string values returned by the functions inside the `__init__.py` file, this means that if the functions do not return strings (enclosed in single or double quotes) or a boolean value (for the `experimental` entry), the metadata entry for that function will not be extracted and if the metadata is mandatory the plugin will be considered invalid.
+
+The new `metadata.txt` file can contain other optional metadata which are read when the package is uploaded and are automatically imported.
+
+Example configuration file::
+
+ ; the next section is mandatory
+ [general]
+ ; start of mandatory metadata
+ name=HelloWorld
+ qgisMinimumVersion=1.8
+ description=This is a plugin for greeting the ...
+ ... (going multiline) world
+ version=version 1.2
+ author=Alessandro Primo
+ email=email@email.com
+ ; end of mandatory metadata
+
+ ; start of optional metadata
+
+ ; experimental flag
+ experimental=True
+
+ changelog=this is a very
+ very
+ very
+ very
+ very
+ very long multiline changelog
+
+ ; tags are in comma separated value format, spaces are allowed
+ tags=wkt,raster,hello world
+
+ ; these metadata can be empty
+ ; in a future version of the web application it will
+ ; be probably possible to create a project on redmine
+ ; if they are not filled
+ homepage=http://www.itopen.it
+ tracker=http://bugs.itopen.it
+ repository=http://www.itopen.it/repo
+ icon=icon.png
+
+
+
+.. rubric:: Footnotes
+
+.. [#f1] 'name', 'description', 'version', 'qgisMinimumVersion', 'author', 'email'
+.. [#f2] Supported by metadata.txt only: 'homepage', 'changelog', 'tracker', 'repository', 'tags'
@@ -19,7 +19,7 @@ class PluginForm(ModelForm):
class Meta:
model = Plugin
- fields = ('description', 'deprecated', 'homepage', 'tracker', 'repository', 'owners', 'tags')
+ fields = ('description', 'author', 'email', 'icon', 'deprecated', 'homepage', 'tracker', 'repository', 'owners', 'tags')
class PluginVersionForm(ModelForm):
@@ -80,11 +80,13 @@ class PackageUploadForm(forms.Form):
"""
Single step upload for new plugins
"""
+ experimental = forms.BooleanField(required=False, label=_('Experimental'), help_text=_('Please check this box if the plugin is experimental. Please note that this field might be overridden by metadata (if present).'))
package = forms.FileField(_('QGIS compressed plugin package'), label=_('Plugin package'), help_text=_('Please select the zipped file of the plugin.'))
- experimental = forms.BooleanField(required=False, label=_('Experimental'), help_text=_('Please check this box if the plugin is experimental.'))
def clean_package(self):
- cleaned_data = self.cleaned_data
+ """
+ Populates cleaned_data with metadata from the zip package
+ """
package = self.cleaned_data.get('package')
try:
self.cleaned_data.update(validator(package))
@@ -3,11 +3,11 @@
<h2>{% trans "Plugin" %}: {{ object.name }}</h2>
<div class="details">
{% if object.deprecated %}<p class="error"><strong>{% trans "This plugin is deprecated!" %}</strong></p>{% endif %}
- <p>{% if object.icon %}<img class="plugin-icon" src="{{ object.icon.url }}" alt="{% trans "Plugin icon" %}" />{% endif %}<strong>{% trans "Description" %}:</strong> {{ object.description }}</p>
+ <p>{% if object.icon %}<img class="plugin-icon" src="{{ object.icon.url }}" alt="{% trans "Plugin icon" %}" />{% endif %}<strong>{% trans "Description" %}:</strong> {{ object.description }}</p>
{% if object.author %}
<p><strong>{% trans "Author"%}:</strong> {{ object.author }}</p>
- {% endif %}
- {% if object.email %}
+ {% endif %}
+ {% if object.email and not user.is_anonymous %}
<p><strong>{% trans "Author's email"%}:</strong> <a href="mailto:{{ object.email }}">{{ object.email }}</a></p>
{% endif %}
<p><strong>{% trans "Maintainer"%}:</strong> <a href="{% url user_details object.created_by %}">{{ object.created_by }}</a></p>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -23,4 +23,4 @@ homepage=http://www.itopen.it
repository=http://www.itopen.it/repo
; change icon...
-icon=icon2.png
+icon=icon.png
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# Import the PyQt and QGIS libraries
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+from qgis.core import *
+
+
+class HelloWorld:
+
+ def __init__(self, iface):
+ # Save reference to the QGIS interface
+ self.iface = iface
+ self.canvas = iface.mapCanvas()
+
+ def initGui(self):
+ # Create action that will start plugin
+ self.action = QAction(QIcon(":/plugins/"), "&HelloWorld", self.iface.mainWindow())
+ # connect the action to the run method
+ QObject.connect(self.action, SIGNAL("activated()"), self.hello_world)
+
+ # Add toolbar button and menu item
+ self.iface.addPluginToMenu("HelloWorld", self.action)
+
+
+ def unload(self):
+ # Remove the plugin menu item and icon
+ self.iface.removePluginMenu("HelloWorld",self.action)
+
+
+
+ # run
+ def hello_world(self):
+ QMessageBox.information(self.iface.mainWindow(), QCoreApplication.translate('HelloWorld', "HelloWorld"), QCoreApplication.translate('HelloWorld', "HelloWorld"))
+ return
+
+
+
+
+if __name__ == "__main__":
+ pass
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+"""
+ This script initializes the plugin, making it known to QGIS.
+"""
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,31 @@
+[general]
+name=HelloWorld
+qgisMinimumVersion=1.8
+description=This is a plugin for greeting the
+ (going multiline) world
+version=version 1.5
+author=Alessandro Quarto
+email=email4@email.com
+
+
+changelog=this is a very
+ very<br/>
+ very
+ very
+ very
+ very long multiline changelog
+
+
+tags=wkt,raster,hello world
+
+tracker=http://bugs.itopen.it
+homepage=http://www.itopen.it
+repository=http://www.itopen.it/repo
+
+
+
+experimental=True
+
+
+; change icon...
+icon=icon.png
@@ -1,2 +1,3 @@
all:
+ @ rm HelloWorld_*.zip
@for i in $$(find . -maxdepth 1 -type d|egrep './.+'|sed -e 's/.\///' ); do cd $$i && zip -r HelloWorld_$$i.zip * && mv *.zip .. && cd ..; done;
@@ -18,7 +18,7 @@
PLUGIN_REQUIRED_METADATA=getattr(settings, 'PLUGIN_REQUIRED_METADATA', ('name', 'description', 'version', 'qgisMinimumVersion', 'author', 'email'))
PLUGIN_OPTIONAL_METADATA=getattr(settings, 'PLUGIN_OPTIONAL_METADATA', ('homepage', 'changelog', 'tracker', 'repository', 'tags', 'deprecated', 'experimental'))
-PLUGIN_BOOLEAN_METADATA=getattr(settings, 'PLUGIN_BOOLEAN_METADATA', ('experimental', 'deprecated'))
+PLUGIN_BOOLEAN_METADATA=getattr(settings, 'PLUGIN_BOOLEAN_METADATA', ('experimental',))
def _read_from_init2(initcontent, initname):
@@ -153,7 +153,7 @@ def validator(package):
metadata.append(('icon_file', icon_file))
- # Transforms booleans flags (experimental and deprecated)
+ # Transforms booleans flags (experimental)
for flag in PLUGIN_BOOLEAN_METADATA:
if flag in dict(metadata):
metadata[metadata.index((flag, dict(metadata)[flag]))] = (flag, dict(metadata)[flag].lower() == 'true' or dict(metadata)[flag].lower() == '1')
@@ -20,6 +20,7 @@
from django.views.generic.list_detail import object_list, object_detail
from django.views.decorators.http import require_POST
+from django.views.decorators.cache import never_cache
from django.core.mail import send_mail
from django.contrib.sites.models import Site
@@ -212,6 +213,8 @@ def plugin_upload(request):
# Apply new values
plugin.name = plugin_data['name']
plugin.description = plugin_data['description']
+ plugin.author = plugin_data['author']
+ plugin.email = plugin_data['email']
plugin.icon = plugin_data['icon']
is_new = False
except Plugin.DoesNotExist:
@@ -344,6 +347,7 @@ def plugin_update(request, package_name):
return render_to_response('plugins/plugin_form.html', { 'form' : form , 'form_title' : _('Edit plugin')}, context_instance=RequestContext(request))
+
def plugins_list(request, queryset, template_name=None, extra_context=None):
"""
Supports per_page
@@ -369,6 +373,7 @@ def my_plugins(request):
queryset = Plugin.objects.filter(owners=request.user).distinct() | Plugin.objects.filter(created_by=request.user).distinct()
return plugins_list(request, queryset, template_name = 'plugins/plugin_list_my.html', extra_context = { 'title' : _('My plugins')})
+
def user_plugins(request, username):
"""
List published plugins created_by user
@@ -694,7 +699,7 @@ def version_detail(request, package_name, version):
###############################################
-
+@never_cache
def xml_plugins(request):
"""
The XML file

0 comments on commit 8da8c29

Please sign in to comment.