51
51
class CharmLinter(Linter):
52
def check_hook(self, hook, hooks_path, required=True, recommended=False):
52
def check_hook(self, hook, hooks_path, recommended=False):
53
53
hook_path = os.path.join(hooks_path, hook)
56
56
mode = os.stat(hook_path)[ST_MODE]
57
57
if not mode & S_IXUSR:
58
self.warn(hook + " not executable")
58
self.info(hook + " not executable")
59
59
with open(hook_path, 'r') as hook_file:
61
61
for line in hook_file:
75
self.err("missing hook " + hook)
77
self.warn("missing recommended hook " + hook)
75
self.info("missing recommended hook " + hook)
80
78
def check_relation_hooks(self, relations, subordinate, hooks_path):
113
111
has_one = has_one or self.check_hook(
114
r + '-relation-changed', hooks_path, required=False)
115
has_one = has_one or self.check_hook(
116
r + '-relation-departed', hooks_path, required=False)
117
has_one = has_one or self.check_hook(
118
r + '-relation-joined', hooks_path, required=False)
119
has_one = has_one or self.check_hook(
120
r + '-relation-broken', hooks_path, required=False)
112
r + '-relation-changed', hooks_path)
113
has_one = has_one or self.check_hook(
114
r + '-relation-departed', hooks_path)
115
has_one = has_one or self.check_hook(
116
r + '-relation-joined', hooks_path)
117
has_one = has_one or self.check_hook(
118
r + '-relation-broken', hooks_path)
122
120
if not has_one and not subordinate:
123
121
self.info("relation " + r + " has no hooks")
283
281
with open(os.path.join(charm_path, 'icon.svg')) as ci:
284
282
icon_sha1.update(ci.read())
285
283
if template_sha1.hexdigest() == icon_sha1.hexdigest():
286
lint.err("Includes template icon.svg file.")
284
lint.warn("Includes template icon.svg file.")
287
285
except IOError as e:
289
287
"Error while opening %s (%s)" %
290
288
(e.filename, e.strerror))
292
290
# Must have a hooks dir
293
291
if not os.path.exists(hooks_path):
294
lint.err("no hooks directory")
292
lint.info("no hooks directory")
296
294
# Must have a copyright file
297
295
if not os.path.exists(os.path.join(charm_path, 'copyright')):
298
lint.err("no copyright file")
296
lint.warn("no copyright file")
300
298
# should have a readme
301
299
root_files = os.listdir(charm_path)
305
303
found_readmes.add(filename)
306
304
if len(found_readmes):
307
305
if 'README.ex' in found_readmes:
308
lint.err("Includes template README.ex file")
306
lint.warn("Includes template README.ex file")
310
308
with open(TEMPLATE_README) as tr:
324
322
if l in readme_content:
325
323
err_msg = ('%s Includes boilerplate '
326
324
'README.ex line %d')
327
lint.err(err_msg % (readme, lc))
325
lint.warn(err_msg % (readme, lc))
328
326
except IOError as e:
330
328
"Error while opening %s (%s)" %
331
329
(e.filename, e.strerror))
382
380
except (TypeError, ValueError):
383
381
lint.warn("revision should be a positive integer")
385
lint.check_hook('install', hooks_path)
386
lint.check_hook('start', hooks_path, required=False,
388
lint.check_hook('stop', hooks_path, required=False,
390
lint.check_hook('config-changed', hooks_path, required=False)
383
lint.check_hook('install', hooks_path, recommended=True)
384
lint.check_hook('start', hooks_path, recommended=True)
385
lint.check_hook('stop', hooks_path, recommended=True)
386
if os.path.exists(os.path.join(charm_path, 'config.yaml')):
387
lint.check_hook('config-changed', hooks_path, recommended=True)
389
lint.check_hook('config-changed', hooks_path)
392
391
lint.err("could not find metadata file for " + charm_name)
393
392
lint.exit_code = -1
395
394
# Should not have autogen test
396
395
if os.path.exists(os.path.join(charm_path, 'tests', '00-autogen')):
397
lint.warn('has templated 00-autogen test file')
396
lint.warn('Includes template test file, tests/00-autogen')
399
398
rev_path = os.path.join(charm_path, 'revision')
400
399
if os.path.exists(rev_path):