-#!/usr/bin/env python2
-# -*- coding: utf-8 -*-
+#!/usr/bin/env python3
#
# lint.py - part of the FDroid server tool
# Copyright (C) 2013-2014 Daniel Martà <mvdan@mvdan.cc>
from argparse import ArgumentParser
import re
-import common
-import metadata
import sys
from sets import Set
+import common
+import metadata
+import rewritemeta
+
config = None
options = None
'Source Code': http_checks,
'Repo': https_enforcings,
'Issue Tracker': http_checks + [
- (re.compile(r'.*github\.com/[^/]+/[^/]+[/]*$'),
+ (re.compile(r'.*github\.com/[^/]+/[^/]+/*$'),
+ "/issues is missing"),
+ (re.compile(r'.*gitlab\.com/[^/]+/[^/]+/*$'),
"/issues is missing"),
],
'Donate': http_checks + [
"Flattr donation methods belong in the FlattrID flag"),
],
'Changelog': http_checks,
+ 'Author Name': [
+ (re.compile(r'^\s'),
+ "Unnecessary leading space"),
+ (re.compile(r'.*\s$'),
+ "Unnecessary trailing space"),
+ ],
'License': [
(re.compile(r'^(|None|Unknown)$'),
"No license specified"),
"No need to specify that the app is for Android"),
(re.compile(r'.*[a-z0-9][.!?]( |$)'),
"Punctuation should be avoided"),
+ (re.compile(r'^\s'),
+ "Unnecessary leading space"),
+ (re.compile(r'.*\s$'),
+ "Unnecessary trailing space"),
],
'Description': [
(re.compile(r'^No description available$'),
for f, checks in regex_checks.iteritems():
for m, r in checks:
v = app.get_field(f)
- if type(v) == str:
+ t = metadata.fieldtype(f)
+ if t == metadata.TYPE_MULTILINE:
+ for l in v.splitlines():
+ if m.match(l):
+ yield "%s at line '%s': %s" % (f, l, r)
+ else:
if v is None:
continue
if m.match(v):
yield "%s '%s': %s" % (f, v, r)
- elif type(v) == list:
- for l in v:
- if m.match(l):
- yield "%s at line '%s': %s" % (f, l, r)
def get_lastbuild(builds):
lowest_vercode = -1
lastbuild = None
for build in builds:
- if not build['disable']:
- vercode = int(build['vercode'])
+ if not build.disable:
+ vercode = int(build.vercode)
if lowest_vercode == -1 or vercode < lowest_vercode:
lowest_vercode = vercode
- if not lastbuild or int(build['vercode']) > int(lastbuild['vercode']):
+ if not lastbuild or int(build.vercode) > int(lastbuild.vercode):
lastbuild = build
return lastbuild
def check_ucm_tags(app):
lastbuild = get_lastbuild(app.builds)
if (lastbuild is not None
- and lastbuild['commit']
+ and lastbuild.commit
and app.UpdateCheckMode == 'RepoManifest'
- and not lastbuild['commit'].startswith('unknown')
- and lastbuild['vercode'] == app.CurrentVersionCode
- and not lastbuild['forcevercode']
- and any(s in lastbuild['commit'] for s in '.,_-/')):
+ and not lastbuild.commit.startswith('unknown')
+ and lastbuild.vercode == app.CurrentVersionCode
+ and not lastbuild.forcevercode
+ and any(s in lastbuild.commit for s in '.,_-/')):
yield "Last used commit '%s' looks like a tag, but Update Check Mode is '%s'" % (
- lastbuild['commit'], app.UpdateCheckMode)
+ lastbuild.commit, app.UpdateCheckMode)
def check_char_limits(app):
limits = config['char_limits']
- summ_chars = len(app.Summary)
- if summ_chars > limits['Summary']:
+ if len(app.Summary) > limits['Summary']:
yield "Summary of length %s is over the %i char limit" % (
- summ_chars, limits['Summary'])
+ len(app.Summary), limits['Summary'])
- desc_charcount = sum(len(l) for l in app.Description)
- if desc_charcount > limits['Description']:
+ if len(app.Description) > limits['Description']:
yield "Description of length %s is over the %i char limit" % (
- desc_charcount, limits['Description'])
+ len(app.Description), limits['Description'])
def check_old_links(app):
yield "Description '%s' is just the app's summary" % app.Summary
seenlines = set()
- for l in app.Description:
+ for l in app.Description.splitlines():
if len(l) < 1:
continue
if l in seenlines:
validchars = ['*', '#']
lchar = ''
lcount = 0
- for l in app.Description:
+ for l in app.Description.splitlines():
if len(l) < 1:
lcount = 0
continue
def check_builds(app):
for build in app.builds:
- if build['disable']:
+ if build.disable:
+ if build.disable.startswith('Generated by import.py'):
+ yield "Build generated by `fdroid import` - remove disable line once ready"
continue
for s in ['master', 'origin', 'HEAD', 'default', 'trunk']:
- if build['commit'] and build['commit'].startswith(s):
- yield "Branch '%s' used as commit in build '%s'" % (s, build['version'])
- for srclib in build['srclibs']:
+ if build.commit and build.commit.startswith(s):
+ yield "Branch '%s' used as commit in build '%s'" % (s, build.version)
+ for srclib in build.srclibs:
ref = srclib.split('@')[1].split('/')[0]
if ref.startswith(s):
yield "Branch '%s' used as commit in srclib '%s'" % (s, srclib)
+ if build.target and build.build_method() == 'gradle':
+ yield "target= has no gradle support"
def main():
# Parse command line...
parser = ArgumentParser(usage="%(prog)s [options] [APPID [APPID ...]]")
common.setup_global_opts(parser)
+ parser.add_argument("-f", "--format", action="store_true", default=False,
+ help="Also warn about formatting issues, like rewritemeta -l")
parser.add_argument("appid", nargs='*', help="app-id in the form APPID")
options = parser.parse_args()
]:
warns += check_func(app)
+ if options.format:
+ if not rewritemeta.proper_format(app):
+ warns.append("Run rewritemeta to fix formatting")
+
if warns:
anywarns = True
for warn in warns:
- print "%s: %s" % (appid, warn)
+ print("%s: %s" % (appid, warn))
if anywarns:
sys.exit(1)