Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions contrib/lint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
libcloud linter

This script checks the libcloud codebase for registered drivers that don't
comply to libcloud API guidelines.
"""

import inspect
import os

import libcloud

import libcloud.compute.providers
from libcloud.compute.base import NodeDriver

import libcloud.dns.providers
from libcloud.dns.base import DNSDriver

import libcloud.loadbalancer.providers
from libcloud.loadbalancer.base import Driver

import libcloud.storage.providers
from libcloud.storage.base import StorageDriver


modules = [
(libcloud.compute.providers, NodeDriver),
(libcloud.dns.providers, DNSDriver),
(libcloud.loadbalancer.providers, Driver),
(libcloud.storage.providers, StorageDriver),
]


warnings = set()

def warning(obj, warning):
source_file = os.path.relpath(inspect.getsourcefile(obj), os.path.dirname(libcloud.__file__))
source_line = inspect.getsourcelines(obj)[1]
if (source_file, source_line, warning) in warnings:
# When the error is actually caused by a mixin or base class we can get dupes...
return
warnings.add((source_file, source_line, warning))
print source_file, source_line, warning

for providers, base, in modules:
core_api = {}
for name, value in inspect.getmembers(base, inspect.ismethod):
if name.startswith("_"):
continue

if name.startswith("ex_"):
warning(value, "Core driver shouldn't haveex_ methods")
continue

args = core_api[name] = inspect.getargspec(value)

for arg in args.args:
if arg.startswith("ex_"):
warning(value, "Core driver method shouldnt have ex_ arguments")


for driver_id in providers.DRIVERS.keys():
driver = providers.get_driver(driver_id)

for name, value in inspect.getmembers(driver, inspect.ismethod):
if name.startswith("_"):
continue

if not name.startswith("ex_") and not name in core_api:
warning(value, "'%s' should be prefixed with ex_ or be private as it is not a core API" % name)
continue


# Only validate arguments of core API's
if name.startswith("ex_"):
continue

argspec = inspect.getargspec(value)

core_args = set(core_api[name].args)
driver_args = set(argspec.args)

for missing in core_args - driver_args:
warning(value, "Core API function should support arg '%s' but doesn't" % missing)

for extra in driver_args - core_args:
if not extra.startswith("ex_"):
warning(value, "Core API function shouldn't take arg '%s'. Should it be prefixed with ex_?" % extra)