<commit_before>from ckan.logic import auth_allow_anonymous_access

import ckan.logic as logic
import ckan.authz as authz
import ckan.plugins.toolkit as toolkit
from ckan.logic.auth import get_resource_object
from ckan.lib.base import _
import ckan.plugins as p
from ckan.logic.auth.create import _check_group_auth
import ckan.logic.auth as logic_auth

from pylons import config

from ckanext.iauth.action import check_loaded_plugin

from ckan.logic.auth import (get_package_object, get_resource_object, get_group_object,get_related_object)

ValidationError = logic.ValidationError
NotAuthorized = toolkit.NotAuthorized
Invalid = toolkit.Invalid

def _check_unauthorized_upload(context, data_dict, owner_org):
    # Return True if UNAUTHORIZED and False if authorized

    special_org_name = ''

    if 'ckanext.iauth.special_org' in config:
        special_org_name = config.get ('ckanext.iauth.special_org')
    else:
        return False

    group_dict = logic.get_action('organization_show')(context, {'id': owner_org})

    if group_dict and 'name' in group_dict:
        if group_dict['name'] !=  special_org_name:
            return False

    if ('upload_local' in data_dict and data_dict['upload_local'] != '')  or ('upload_remote' in data_dict and data_dict['upload_remote'] != '') :
            return True

    return False

def resource_create(context, data_dict):

    #################################################################
    ### From CKAN Core
    model = context['model']
    user = context.get('user')
    package_id = data_dict.get('package_id')
    if not package_id and data_dict.get('id'):
        # This can happen when auth is deferred, eg from `resource_view_create`
        resource = logic_auth.get_resource_object(context, data_dict)
        package_id = resource.package_id

    if not package_id:
        raise logic.NotFound(
            _('No dataset id provided, cannot check auth.')
        )

    # check authentication against package
    pkg = model.Package.get(package_id)
    if not pkg:
        raise logic.NotFound(
            _('No package found for this resource, cannot check auth.')
        )

    pkg_dict = {'id': pkg.id}
    authorized = authz.is_authorized('package_update', context, pkg_dict).get('success')

    ######## Modification for special_org, Anja, 18.8.17
    # check unauthrized upload for memebers of special_org
    if  _check_unauthorized_upload(context, data_dict, pkg.owner_org):
        errors = { 'url': [u'Members of CCCA Extern are not authorized to upload resources']}
        data_dict['upload_local'] = ''
        data_dict['upload_remote'] = ''
        # We need to delete the field, because localimp validator only requires "non-empty"
        # and user can just press again "add" or "update"
        if 'url' in data_dict:
            data_dict['url'] = ''
        raise ValidationError(errors)
    ######## End Modification for special_org, Anja, 18.8.17

    if not authorized:
        return {'success': False,
                'msg': _('User %s not authorized to create resources on dataset %s') %
                        (str(user), package_id)}
    else:
        return {'success': True}
    ### From CKAN Core END
    #################################################################

@logic.auth_allow_anonymous_access
def package_show(context, data_dict):
    #########################################################
    # From Core CKAN ----
    user = context.get('user')
    package = get_package_object(context, data_dict)
    # draft state indicates package is still in the creation process
    # so we need to check we have creation rights.
    if package.state.startswith('draft'):
        auth = authz.is_authorized('package_update',
                                       context, data_dict)
        authorized = auth.get('success')
    # new elif Anja, 17.8.17; let otherwise to problems with create_subset
    elif package.state.startswith('deleted'):
        return {'success': True}
    elif package.owner_org is None and package.state == 'active':
        return {'success': True}
    else:
        # anyone can see a public package
        if not package.private and package.state == 'active':
            return {'success': True}
        authorized = authz.has_user_permission_for_group_or_org(
            package.owner_org, user, 'read')

    ####################### Modification ###########################
    # Every normal (Editor) user is only allowed to see his own private packages
    if package.private and authorized:

        # check Admin
        authorized_admin = authz.has_user_permission_for_group_or_org(package.owner_org, user, 'member_create')

        if  authorized_admin:
            return {'success': True}

        # Editor remains; check if we try to edit our own dataset
        user_info = context.get('auth_user_obj')

        if user_info == None:  # Anon User - should not happen here
            authorized = False

        #Editors and Members left
        if authorized:  # check if we need to restrict access
            if user_info.id != package.creator_user_id and  user_info.email != package.maintainer_email and user_info.email != package.author_email:
                #errors = { 'private': [u'Not authorized to to see private datasets']}

                # Leider geht das hier alles nicht :-(
                #raise Exception("TEst")
                #raise NotAuthorized("Test")
                #raise ValidationError("Test")

                authorized = False

    ####################### Modification END ###########################

    if not authorized:
        return {'success': False, 'msg': _('User %s not authorized to read package %s') % (user, package.id)}
    else:
        return {'success': True}

    # From Core CKAN ----  END
    ###############################################################

#@logic.auth_allow_anonymous_access
def package_update(context, data_dict):

    package = logic_auth.get_package_object(context, data_dict)
    # Handle
    if check_loaded_plugin (context, {'name':'handle'}):
        if package.private is not None and package.private is False and data_dict is not None and data_dict.get('private', '') == 'True':
            return {'success': False,
                    'msg': 'Public datasets cannot be set private again'}

    #Thredds - subset
    if check_loaded_plugin (context, {'name':'thredds'}):
        from ckanext.thredds import helpers
        if package.private is not None and package.private is True and data_dict is not None and data_dict.get('private', '') == 'False':
            subset_uniqueness = helpers.check_subset_uniqueness(package.id)

            if len(subset_uniqueness) > 0:
                return {'success': False,
                        'msg': 'Dataset cannot be set public as it contains a subset, which was already published'}
    # check Admin
    user = context.get('user')
    authorized_admin = authz.has_user_permission_for_group_or_org(package.owner_org, user, 'member_create')

    if  authorized_admin:
        return {'success': True}

    # Editor_mod
    editor_restricted = False
    if 'ckanext.iauth.editor_modified' in config:
        editor_mod = config.get('ckanext.iauth.editor_modified')
        if editor_mod == 'true' or editor_mod == 'True':
           editor_restricted = True

    # From Core CKAN ---- # Modified for Restricted Editor - editor_mod
    user = context.get('user')
    package = logic_auth.get_package_object(context, data_dict)

    if package.owner_org:
        # if there is an owner org then we must have update_dataset
        # permission for that organization
        check1 = authz.has_user_permission_for_group_or_org(
            package.owner_org, user, 'update_dataset'
        )
        ########################################################################
        #### Modification for restricted editor: editor_mod flag - Anja 13.7.17
        if check1 and editor_restricted:

            user_info = context.get('auth_user_obj')

            #check if we are an Organisation Admin - sysadmins do not come into this function at all!!
            owner_org = package.owner_org
            local_access = False
            org_list = toolkit.get_action('organization_list_for_user')({}, {"id": user_info.id, "permission": "member_create"})
            for x in org_list:
                if owner_org in x.values():
                    local_access = True

            if not local_access:   # We are Editor: restrict access
                # Editors only allowed to edit own packages
                if user_info.id == package.creator_user_id or user_info.email == package.maintainer_email or user_info.email == package.author_email:
                    check1 = True
                else:
                    check1 = False

        #### Modification for restricted editor: editor_mod flag - Anja 13.7.17 END
        ###########################################################################
    else:
        # If dataset is not owned then we can edit if config permissions allow
        if authz.auth_is_anon_user(context):
            check1 = all(authz.check_config_permission(p) for p in (
                'anon_create_dataset',
                'create_dataset_if_not_in_organization',
                'create_unowned_dataset',
                ))
        else:
            check1 = all(authz.check_config_permission(p) for p in (
                'create_dataset_if_not_in_organization',
                'create_unowned_dataset',
                )) or authz.has_user_permission_for_some_org(
                user, 'create_dataset')
    if not check1:
        return {'success': False,
                'msg': _('User %s not authorized to edit package %s') %
                        (str(user), package.id)}
    else:
        check2 = _check_group_auth(context, data_dict)
        if not check2:
            return {'success': False,
                    'msg': _('User %s not authorized to edit these groups') %
                            (str(user))}

    return {'success': True}
    # From Core CKAN END

#@logic.auth_allow_anonymous_access
def resource_update(context, data_dict):

    resource = logic_auth.get_resource_object(context, data_dict)

    #resourceversions
    if check_loaded_plugin (context, {'name':'resourceversions'}):

        upload = False
        if 'upload' in data_dict and data_dict['upload'] != "" or 'upload_local' in data_dict and data_dict['upload_local'] != "" or 'upload_remote' in data_dict and data_dict['upload_remote'] != "":
            upload = True

        if upload or 'url' in data_dict and "/" in data_dict['url'] and data_dict['url'] != resource.url:
            # check if resource has a newer version
            if 'newer_version' in resource.extras and resource.extras['newer_version'] != "":
                errors = { 'url': [u'Older versions cannot be updated']}
                raise ValidationError(errors)
                return {'success': False, 'msg': 'Older versions cannot be updated'}
            # check if this is a subset, then it cannot create a new version like that

            if check_loaded_plugin (context, {'name':'thredds'}):
                if 'subset_of' in resource.extras and resource.extras['subset_of'] != "":
                    errors = { 'url': [u'Please create only new versions from the original resource']}
                    raise ValidationError(errors)
                    return {'success': False, 'msg': 'Please create only new versions from the original resource'}

    # From Core
    model = context['model']
    user = context.get('user')
    #resource = logic_auth.get_resource_object(context, data_dict)

    # check authentication against package
    pkg = model.Package.get(resource.package_id)
    if not pkg:
        raise logic.NotFound(
            _('No package found for this resource, cannot check auth.')
        )

    pkg_dict = {'id': pkg.id}
    authorized = authz.is_authorized('package_update', context, pkg_dict).get('success')

    if not authorized:
        return {'success': False,
                'msg': _('User %s not authorized to edit resource %s') %
                        (str(user), resource.id)}
    else:
        #return {'success': True}

        ######## Modification for special_org, Anja, 18.8.17
        # check unauthorized upload for members of special_org
        if  _check_unauthorized_upload(context, data_dict, pkg.owner_org):
            errors = { 'url': [u'Members of CCCA Extern are not authorized to upload resources']}
            data_dict['upload_local'] = ''
            data_dict['upload_remote'] = ''
            # We need to delete the field, because localimp validator only requires "non-empty"
            # and user can just press again "add" or "update"
            if 'url' in data_dict:
                data_dict['url'] = ''
            raise ValidationError(errors)
            return {'success': False,
                    'msg': _('Members of CCCA Extern are not authorized to upload resources')}

        ######## End Modification for special_org, Anja, 18.8.17

        return {'success': True}
    # From Core END

#@logic.auth_allow_anonymous_access
def package_delete(context, data_dict):

    package = toolkit.get_action('package_show')(data_dict={'id': data_dict['id']})

    # Handle
    if check_loaded_plugin (context, {'name':'handle'}):
        # check if package is public
        if package['private'] is False:
            return {'success': False, 'msg': 'Public datasets cannot be deleted'}

    # From CORE
    # Defer authorization for package_delete to package_update, as deletions
    # are essentially changing the state field
    #return _auth_update.package_update(context, data_dict)
    # From CORE END

    #Renamed ...
    return authz.is_authorized('package_update', context, data_dict)

#@logic.auth_allow_anonymous_access
def resource_delete(context, data_dict):

    # Handle
    if check_loaded_plugin (context, {'name':'handle'}):

        resource = get_resource_object(context, data_dict)

        # check authentication against package
        pkg = model.Package.get(resource.package_id)

        if not pkg:
            raise logic.NotFound(_('No package found for this resource, cannot check auth.'))

        # check if package is public
        if pkg['private'] is False:
            return {'success': False, 'msg': 'Public resources cannot be deleted'}

    # From CORE
    model = context['model']
    user = context.get('user')
    resource = get_resource_object(context, data_dict)

    # check authentication against package
    pkg = model.Package.get(resource.package_id)
    if not pkg:
        raise logic.NotFound(_('No package found for this resource, cannot check auth.'))

    pkg_dict = {'id': pkg.id}
    authorized = package_delete(context, pkg_dict).get('success')

    if not authorized:
        return {'success': False, 'msg': _('User %s not authorized to delete resource %s') % (user, resource.id)}
    else:
        return {'success': True}
    # From CORE End
<commit_msg>first adjustments<commit_after>from ckan.logic import auth_allow_anonymous_access

import ckan.logic as logic
import ckan.authz as authz
import ckan.plugins.toolkit as toolkit
from ckan.logic.auth import get_resource_object
from ckan.lib.base import _
import ckan.plugins as p
from ckan.logic.auth.create import _check_group_auth
import ckan.logic.auth as logic_auth

from pylons import config

from ckanext.iauth.action import check_loaded_plugin

from ckan.logic.auth import (get_package_object, get_resource_object, get_group_object,get_related_object)

ValidationError = logic.ValidationError
NotAuthorized = toolkit.NotAuthorized
Invalid = toolkit.Invalid

def _check_unauthorized_upload(context, data_dict, owner_org):
    # Return True if UNAUTHORIZED and False if authorized

    special_org_name = ''

    if 'ckanext.iauth.special_org' in config:
        special_org_name = config.get ('ckanext.iauth.special_org')
    else:
        return False

    group_dict = logic.get_action('organization_show')(context, {'id': owner_org})

    if group_dict and 'name' in group_dict:
        if group_dict['name'] !=  special_org_name:
            return False

    if ('upload_local' in data_dict and data_dict['upload_local'] != '')  or ('upload_remote' in data_dict and data_dict['upload_remote'] != '') :
            return True

    return False

def resource_create(context, data_dict):

    #################################################################
    ### From CKAN Core
    model = context['model']
    user = context.get('user')
    package_id = data_dict.get('package_id')
    if not package_id and data_dict.get('id'):
        # This can happen when auth is deferred, eg from `resource_view_create`
        resource = logic_auth.get_resource_object(context, data_dict)
        package_id = resource.package_id

    if not package_id:
        raise logic.NotFound(
            _('No dataset id provided, cannot check auth.')
        )

    # check authentication against package
    pkg = model.Package.get(package_id)
    if not pkg:
        raise logic.NotFound(
            _('No package found for this resource, cannot check auth.')
        )

    pkg_dict = {'id': pkg.id}
    authorized = authz.is_authorized('package_update', context, pkg_dict).get('success')

    ######## Modification for special_org, Anja, 18.8.17
    # check unauthrized upload for memebers of special_org
    if  _check_unauthorized_upload(context, data_dict, pkg.owner_org):
        errors = { 'url': [u'Members of CCCA Extern are not authorized to upload resources']}
        data_dict['upload_local'] = ''
        data_dict['upload_remote'] = ''
        # We need to delete the field, because localimp validator only requires "non-empty"
        # and user can just press again "add" or "update"
        if 'url' in data_dict:
            data_dict['url'] = ''
        raise ValidationError(errors)
    ######## End Modification for special_org, Anja, 18.8.17

    if not authorized:
        return {'success': False,
                'msg': _('User %s not authorized to create resources on dataset %s') %
                        (str(user), package_id)}
    else:
        return {'success': True}
    ### From CKAN Core END
    #################################################################

@logic.auth_allow_anonymous_access
def package_show(context, data_dict):
    #########################################################
    # From Core CKAN ----
    user = context.get('user')
    package = get_package_object(context, data_dict)
    # draft state indicates package is still in the creation process
    # so we need to check we have creation rights.
    if package.state.startswith('draft'):
        auth = authz.is_authorized('package_update',
                                       context, data_dict)
        authorized = auth.get('success')
    # new elif Anja, 17.8.17; let otherwise to problems with create_subset
    elif package.state.startswith('deleted'):
        return {'success': True}
    elif package.owner_org is None and package.state == 'active':
        return {'success': True}
    else:
        # anyone can see a public package
        if not package.private and package.state == 'active':
            return {'success': True}
        authorized = authz.has_user_permission_for_group_or_org(
            package.owner_org, user, 'read')

    ####################### Modification ###########################
    # Every normal (Editor) user is only allowed to see his own private packages
    if package.private and authorized:

        # check Admin
        authorized_admin = authz.has_user_permission_for_group_or_org(package.owner_org, user, 'member_create')

        if  authorized_admin:
            return {'success': True}

        # Editor remains; check if we try to edit our own dataset
        user_info = context.get('auth_user_obj')

        if user_info == None:  # Anon User - should not happen here
            authorized = False

        #Editors and Members left
        if authorized:  # check if we need to restrict access
            if user_info.id != package.creator_user_id and  user_info.email != package.maintainer_email and user_info.email != package.author_email:
                #errors = { 'private': [u'Not authorized to to see private datasets']}

                # Leider geht das hier alles nicht :-(
                #raise Exception("TEst")
                #raise NotAuthorized("Test")
                #raise ValidationError("Test")

                authorized = False

    ####################### Modification END ###########################

    if not authorized:
        return {'success': False, 'msg': _('User %s not authorized to read package %s') % (user, package.id)}
    else:
        return {'success': True}

    # From Core CKAN ----  END
    ###############################################################

#@logic.auth_allow_anonymous_access
def package_update(context, data_dict):

    package = logic_auth.get_package_object(context, data_dict)
    # Handle
    if check_loaded_plugin (context, {'name':'handle'}):
        if package.private is not None and package.private is False and data_dict is not None and data_dict.get('private', '') == 'True':
            return {'success': False,
                    'msg': 'Public datasets cannot be set private again'}

    #Thredds - subset
    # TODO
    if check_loaded_plugin (context, {'name':'thredds'}):
        from ckanext.thredds import helpers
        if package.private is not None and package.private is True and data_dict is not None and data_dict.get('private', '') == 'False':
            subset_uniqueness = helpers.check_subset_uniqueness(package.id)

            if len(subset_uniqueness) > 0:
                return {'success': False,
                        'msg': 'Dataset cannot be set public as it contains a subset, which was already published'}
    # check Admin
    user = context.get('user')
    authorized_admin = authz.has_user_permission_for_group_or_org(package.owner_org, user, 'member_create')

    if  authorized_admin:
        return {'success': True}

    # Editor_mod
    editor_restricted = False
    if 'ckanext.iauth.editor_modified' in config:
        editor_mod = config.get('ckanext.iauth.editor_modified')
        if editor_mod == 'true' or editor_mod == 'True':
           editor_restricted = True

    # From Core CKAN ---- # Modified for Restricted Editor - editor_mod
    user = context.get('user')
    package = logic_auth.get_package_object(context, data_dict)

    if package.owner_org:
        # if there is an owner org then we must have update_dataset
        # permission for that organization
        check1 = authz.has_user_permission_for_group_or_org(
            package.owner_org, user, 'update_dataset'
        )
        ########################################################################
        #### Modification for restricted editor: editor_mod flag - Anja 13.7.17
        if check1 and editor_restricted:

            user_info = context.get('auth_user_obj')

            #check if we are an Organisation Admin - sysadmins do not come into this function at all!!
            owner_org = package.owner_org
            local_access = False
            org_list = toolkit.get_action('organization_list_for_user')({}, {"id": user_info.id, "permission": "member_create"})
            for x in org_list:
                if owner_org in x.values():
                    local_access = True

            if not local_access:   # We are Editor: restrict access
                # Editors only allowed to edit own packages
                if user_info.id == package.creator_user_id or user_info.email == package.maintainer_email or user_info.email == package.author_email:
                    check1 = True
                else:
                    check1 = False

        #### Modification for restricted editor: editor_mod flag - Anja 13.7.17 END
        ###########################################################################
    else:
        # If dataset is not owned then we can edit if config permissions allow
        if authz.auth_is_anon_user(context):
            check1 = all(authz.check_config_permission(p) for p in (
                'anon_create_dataset',
                'create_dataset_if_not_in_organization',
                'create_unowned_dataset',
                ))
        else:
            check1 = all(authz.check_config_permission(p) for p in (
                'create_dataset_if_not_in_organization',
                'create_unowned_dataset',
                )) or authz.has_user_permission_for_some_org(
                user, 'create_dataset')
    if not check1:
        return {'success': False,
                'msg': _('User %s not authorized to edit package %s') %
                        (str(user), package.id)}
    else:
        check2 = _check_group_auth(context, data_dict)
        if not check2:
            return {'success': False,
                    'msg': _('User %s not authorized to edit these groups') %
                            (str(user))}

    return {'success': True}
    # From Core CKAN END

#@logic.auth_allow_anonymous_access
def resource_update(context, data_dict):

    resource = logic_auth.get_resource_object(context, data_dict)
    print(resource)
    pkg = toolkit.get_action('package_show')(context, {'id': resource.package_id})

    # resourceversions
    if check_loaded_plugin (context, {'name':'resourceversions'}):
        try:
            newer_versions = [element['id'] for element in pkg['relations'] if element['relation'] == 'has_version']
        except:
            newer_versions = []

        upload = False
        if 'upload' in data_dict and data_dict['upload'] != "" or 'upload_local' in data_dict and data_dict['upload_local'] != "" or 'upload_remote' in data_dict and data_dict['upload_remote'] != "":
            upload = True

        if upload or 'url' in data_dict and "/" in data_dict['url'] and data_dict['url'] != resource.url:
            # check if resource has a newer version
            if len(newer_versions) > 0:
                errors = { 'url': [u'Older versions cannot be updated']}
                raise ValidationError(errors)
                return {'success': False, 'msg': 'Older versions cannot be updated'}
            # check if this is a subset, then it cannot create a new version like that

    # Thredds - subset
    if check_loaded_plugin(context, {'name': 'thredds'}):
        from ckanext.thredds import helpers
        if helpers.get_parent_dataset(pkg['id']) is not None:
            return {'success': False,
                    'msg': _('Subsets cannot be modified')}

    # From Core
    model = context['model']
    user = context.get('user')
    #resource = logic_auth.get_resource_object(context, data_dict)

    # check authentication against package
    pkg = model.Package.get(resource.package_id)
    if not pkg:
        raise logic.NotFound(
            _('No package found for this resource, cannot check auth.')
        )

    pkg_dict = {'id': pkg.id}
    authorized = authz.is_authorized('package_update', context, pkg_dict).get('success')

    if not authorized:
        return {'success': False,
                'msg': _('User %s not authorized to edit resource %s') %
                        (str(user), resource.id)}
    else:
        #return {'success': True}

        ######## Modification for special_org, Anja, 18.8.17
        # check unauthorized upload for members of special_org
        if  _check_unauthorized_upload(context, data_dict, pkg.owner_org):
            errors = { 'url': [u'Members of CCCA Extern are not authorized to upload resources']}
            data_dict['upload_local'] = ''
            data_dict['upload_remote'] = ''
            # We need to delete the field, because localimp validator only requires "non-empty"
            # and user can just press again "add" or "update"
            if 'url' in data_dict:
                data_dict['url'] = ''
            raise ValidationError(errors)
            return {'success': False,
                    'msg': _('Members of CCCA Extern are not authorized to upload resources')}

        ######## End Modification for special_org, Anja, 18.8.17

        return {'success': True}
    # From Core END

#@logic.auth_allow_anonymous_access
def package_delete(context, data_dict):

    package = toolkit.get_action('package_show')(data_dict={'id': data_dict['id']})

    # Handle
    if check_loaded_plugin (context, {'name':'handle'}):
        # check if package is public
        if package['private'] is False:
            return {'success': False, 'msg': 'Public datasets cannot be deleted'}

    # From CORE
    # Defer authorization for package_delete to package_update, as deletions
    # are essentially changing the state field
    #return _auth_update.package_update(context, data_dict)
    # From CORE END

    #Renamed ...
    return authz.is_authorized('package_update', context, data_dict)

#@logic.auth_allow_anonymous_access
def resource_delete(context, data_dict):
    model = context['model']
    user = context.get('user')
    resource = get_resource_object(context, data_dict)

    # Handle
    if check_loaded_plugin (context, {'name':'handle'}):

        resource = get_resource_object(context, data_dict)

        # check authentication against package
        pkg = model.Package.get(resource.package_id)

        if not pkg:
            raise logic.NotFound(_('No package found for this resource, cannot check auth.'))

        # check if package is public
        if pkg['private'] is False:
            return {'success': False, 'msg': 'Public resources cannot be deleted'}

    pkg = toolkit.get_action('package_show')(context, {'id': resource['package_id']})

    # resourceversions
    if check_loaded_plugin(context, {'name': 'resourceversions'}):
        from ckanext.thredds import helpers
        versions = helpers.get_versions(pkg['id'])

        if len(versions) > 0:
            return {'success': False, 'msg': 'resource versions cannot be deleted'}

    # Thredds - subset
    if check_loaded_plugin(context, {'name': 'thredds'}):
        from ckanext.thredds import helpers
        if helpers.get_parent_dataset(resource['package_id']) is not None:
            return {'success': False,
                    'msg': _('resource subsets cannot be deleted')}

    # From CORE

    # check authentication against package
    pkg = model.Package.get(resource.package_id)
    if not pkg:
        raise logic.NotFound(_('No package found for this resource, cannot check auth.'))

    pkg_dict = {'id': pkg.id}
    authorized = package_delete(context, pkg_dict).get('success')

    if not authorized:
        return {'success': False, 'msg': _('User %s not authorized to delete resource %s') % (user, resource.id)}
    else:
        return {'success': True}
    # From CORE End
<|endoftext|>


<commit_before>from django.contrib import admin
from clusters.models import *
from clusters.actions import export_as_csv

admin.site.add_action(export_as_csv, 'export_selected objects')

admin.site.register(Community)

class ClusterAdmin(admin.ModelAdmin):
    list_display = ('name', 'community')

admin.site.register(Cluster, ClusterAdmin)

class FunctionResourceInline(admin.TabularInline):
    model = FunctionResourceType

class IncomingFunctionResourceFlowInline(admin.TabularInline):
    model = FunctionResourceFlow
    fk_name = 'to_function'
    verbose_name = 'incoming flow'
    verbose_name_plural = 'incoming flows'

class OutgoingFunctionResourceFlowInline(admin.TabularInline):
    model = FunctionResourceFlow
    fk_name = 'from_function'
    verbose_name = 'outgoing flow'
    verbose_name_plural = 'outgoing flows'

class EconomicFunctionAdmin(admin.ModelAdmin):
    list_display = ('name', 'cluster', 'aspect')
    list_filter = ['cluster',]
    search_fields = ['name', 'cluster__name']
    list_editable = ['aspect',]
    inlines = [
               FunctionResourceInline,
               IncomingFunctionResourceFlowInline,
               OutgoingFunctionResourceFlowInline,
               ]

admin.site.register(EconomicFunction, EconomicFunctionAdmin)

class AgentFunctionInline(admin.TabularInline):
    model = AgentFunction

class AgentResourceInline(admin.TabularInline):
    model = AgentResourceType

class IncomingAgentResourceFlowInline(admin.TabularInline):
    model = AgentResourceFlow
    fk_name = 'to_function'
    verbose_name = 'incoming flow'
    verbose_name_plural = 'incoming flows'

class OutgoingAgentResourceFlowInline(admin.TabularInline):
    model = AgentResourceFlow
    fk_name = 'from_function'
    verbose_name = 'outgoing flow'
    verbose_name_plural = 'outgoing flows'

class EconomicAgentAdmin(admin.ModelAdmin):
    list_display = ('name', 'address')
    search_fields = ['name', 'address']
    inlines = [ AgentFunctionInline,
               AgentResourceInline,
               ]

admin.site.register(EconomicAgent, EconomicAgentAdmin)

class AgentFunctionAdmin(admin.ModelAdmin):
    list_display = ('agent', 'function')
    inlines = [IncomingAgentResourceFlowInline,
               OutgoingAgentResourceFlowInline,
               ]

admin.site.register(AgentFunction, AgentFunctionAdmin)

class EconomicResourceTypeAdmin(admin.ModelAdmin):
    list_display = ('name', 'parent')
    list_filter = ['parent']
    search_fields = ['name',]

admin.site.register(EconomicResourceType, EconomicResourceTypeAdmin)

class CommunityResourceTypeAdmin(admin.ModelAdmin):
    list_display = ('community', 'resource_type', 'aspect')
    list_filter = ['community']
    list_editable = ['aspect',]
    search_fields = ['community__name', 'resource_type__name']

admin.site.register(CommunityResourceType, CommunityResourceTypeAdmin)

class CommunityAgentAdmin(admin.ModelAdmin):
    list_display = ('community', 'agent')
    list_filter = ['community']
    search_fields = ['community__name', 'agent__name']

admin.site.register(CommunityAgent, CommunityAgentAdmin)

admin.site.register(SiteSettings)
admin.site.register(Unit)
<commit_msg>add admin inline for AgentFunctionResourceType<commit_after>from django.contrib import admin
from clusters.models import *
from clusters.actions import export_as_csv

admin.site.add_action(export_as_csv, 'export_selected objects')

admin.site.register(Community)

class ClusterAdmin(admin.ModelAdmin):
    list_display = ('name', 'community')

admin.site.register(Cluster, ClusterAdmin)

class FunctionResourceInline(admin.TabularInline):
    model = FunctionResourceType

class IncomingFunctionResourceFlowInline(admin.TabularInline):
    model = FunctionResourceFlow
    fk_name = 'to_function'
    verbose_name = 'incoming flow'
    verbose_name_plural = 'incoming flows'

class OutgoingFunctionResourceFlowInline(admin.TabularInline):
    model = FunctionResourceFlow
    fk_name = 'from_function'
    verbose_name = 'outgoing flow'
    verbose_name_plural = 'outgoing flows'

class EconomicFunctionAdmin(admin.ModelAdmin):
    list_display = ('name', 'cluster', 'aspect')
    list_filter = ['cluster',]
    search_fields = ['name', 'cluster__name']
    list_editable = ['aspect',]
    inlines = [
               FunctionResourceInline,
               IncomingFunctionResourceFlowInline,
               OutgoingFunctionResourceFlowInline,
               ]

admin.site.register(EconomicFunction, EconomicFunctionAdmin)

class AgentFunctionInline(admin.TabularInline):
    model = AgentFunction

class AgentFunctionResourceInline(admin.TabularInline):
    model = AgentFunctionResourceType

class IncomingAgentResourceFlowInline(admin.TabularInline):
    model = AgentResourceFlow
    fk_name = 'to_function'
    verbose_name = 'incoming flow'
    verbose_name_plural = 'incoming flows'

class OutgoingAgentResourceFlowInline(admin.TabularInline):
    model = AgentResourceFlow
    fk_name = 'from_function'
    verbose_name = 'outgoing flow'
    verbose_name_plural = 'outgoing flows'

class EconomicAgentAdmin(admin.ModelAdmin):
    list_display = ('name', 'address')
    search_fields = ['name', 'address']
    inlines = [ AgentFunctionInline,
               AgentResourceInline,
               ]

admin.site.register(EconomicAgent, EconomicAgentAdmin)

class AgentFunctionAdmin(admin.ModelAdmin):
    list_display = ('agent', 'function')
    inlines = [AgentFunctionResourceInline,
               IncomingAgentResourceFlowInline,
               OutgoingAgentResourceFlowInline,
               ]

admin.site.register(AgentFunction, AgentFunctionAdmin)

class EconomicResourceTypeAdmin(admin.ModelAdmin):
    list_display = ('name', 'parent')
    list_filter = ['parent']
    search_fields = ['name',]

admin.site.register(EconomicResourceType, EconomicResourceTypeAdmin)

class CommunityResourceTypeAdmin(admin.ModelAdmin):
    list_display = ('community', 'resource_type', 'aspect')
    list_filter = ['community']
    list_editable = ['aspect',]
    search_fields = ['community__name', 'resource_type__name']

admin.site.register(CommunityResourceType, CommunityResourceTypeAdmin)

class CommunityAgentAdmin(admin.ModelAdmin):
    list_display = ('community', 'agent')
    list_filter = ['community']
    search_fields = ['community__name', 'agent__name']

admin.site.register(CommunityAgent, CommunityAgentAdmin)

admin.site.register(SiteSettings)
admin.site.register(Unit)
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
###############################################################################
#
# Copyright (C) 2013-Today  Carlos Eduardo Vercelino - CLVsol
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################

from __future__ import print_function

import sqlite3

def myo_person_log_export_sqlite(client, args, db_path, table_name):

    conn = sqlite3.connect(db_path)
    conn.text_factory = str

    cursor = conn.cursor()
    try:
        cursor.execute('''DROP TABLE ''' + table_name + ''';''')
    except Exception as e:
        print('------->', e)
    cursor.execute('''
        CREATE TABLE ''' + table_name + ''' (
            id INTEGER NOT NULL PRIMARY KEY,
            person_id,
            user_id,
            date_log,
            values_,
            action,
            notes,
            new_id INTEGER
            );
    ''')

    client.context = {'active_test': False}
    myo_person_log = client.model('myo.person.log')
    person_log_browse = myo_person_log.browse(args)

    person_log_count = 0
    for person_log in person_log_browse:
        person_log_count += 1

        print(
            person_log_count, person_log.id, person_log.values,
            person_log.date_log, person_log.notes
        )

        person_id = None
        if person_log.person_id:
            person_id = person_log.person_id.id

        user_id = None
        if person_log.user_id:
            user_id = person_log.user_id.id

        notes = None
        if person_log.notes:
            notes = person_log.notes

        cursor.execute('''
                       INSERT INTO ''' + table_name + '''(
                           id,
                           person_id,
                           user_id,
                           date_log,
                           values_,
                           action,
                           notes
                           )
                       VALUES(?,?,?,?,?,?,?)''',
                       (person_log.id,
                        person_id,
                        user_id,
                        person_log.date_log,
                        person_log.values,
                        person_log.action,
                        notes
                        )
                       )

    conn.commit()
    conn.close()

    print()
    print('--> person_log_count: ', person_log_count)

def clv_person_log_import_sqlite(client, args, db_path, table_name, person_table_name, res_users_table_name):

    person_log_model = client.model('clv.person.log')
    person_log_browse = person_log_model.browse([])
    person_log_browse.unlink()

    conn = sqlite3.connect(db_path)
    conn.row_factory = sqlite3.Row

    cursor = conn.cursor()

    cursor2 = conn.cursor()

    data = cursor.execute('''
        SELECT
            id,
            person_id,
            user_id,
            date_log,
            values_,
            action,
            notes,
            new_id
        FROM ''' + table_name + '''
        ORDER BY id;
    ''')

    print(data)
    print([field[0] for field in cursor.description])

    person_log_count = 0
    for row in cursor:
        person_log_count += 1

        print(
            person_log_count, row['id'], row['person_id'], row['user_id'], row['date_log'],
            row['values_'], row['action'], row['notes']
        )

        if row['person_id']:

            person_id = row['person_id']

            cursor2.execute(
                '''
                SELECT new_id
                FROM ''' + person_table_name + '''
                WHERE id = ?;''',
                (person_id,
                 )
            )
            person_id = cursor2.fetchone()[0]

        if row['user_id']:

            user_id = row['user_id']

            cursor2.execute(
                '''
                SELECT new_id
                FROM ''' + res_users_table_name + '''
                WHERE id = ?;''',
                (user_id,
                 )
            )
            user_id = cursor2.fetchone()[0]
            if user_id is None:
                user_id = 1

        values = {
            'person_id': person_id,
            'user_id': user_id,
            'date_log': row['date_log'],
            'values': row['values_'],
            'action': row['action'],
            'notes': row['notes'],
        }
        person_log_id = person_log_model.create(values).id

        cursor2.execute(
            '''
            UPDATE ''' + table_name + '''
            SET new_id = ?
            WHERE id = ?;''',
            (person_log_id,
             row['id']
             )
        )

    conn.commit()
    conn.close()

    print()
    print('--> person_log_count: ', person_log_count)
<commit_msg>[IMP] clv_person_log.py (ADD clv_person_log_export_sqlite_10)<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
###############################################################################
#
# Copyright (C) 2013-Today  Carlos Eduardo Vercelino - CLVsol
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################

from __future__ import print_function

import sqlite3

def myo_person_log_export_sqlite(client, args, db_path, table_name):

    conn = sqlite3.connect(db_path)
    conn.text_factory = str

    cursor = conn.cursor()
    try:
        cursor.execute('''DROP TABLE ''' + table_name + ''';''')
    except Exception as e:
        print('------->', e)
    cursor.execute('''
        CREATE TABLE ''' + table_name + ''' (
            id INTEGER NOT NULL PRIMARY KEY,
            person_id,
            user_id,
            date_log,
            values_,
            action,
            notes,
            new_id INTEGER
            );
    ''')

    client.context = {'active_test': False}
    myo_person_log = client.model('myo.person.log')
    person_log_browse = myo_person_log.browse(args)

    person_log_count = 0
    for person_log in person_log_browse:
        person_log_count += 1

        print(
            person_log_count, person_log.id, person_log.values,
            person_log.date_log, person_log.notes
        )

        person_id = None
        if person_log.person_id:
            person_id = person_log.person_id.id

        user_id = None
        if person_log.user_id:
            user_id = person_log.user_id.id

        notes = None
        if person_log.notes:
            notes = person_log.notes

        cursor.execute('''
                       INSERT INTO ''' + table_name + '''(
                           id,
                           person_id,
                           user_id,
                           date_log,
                           values_,
                           action,
                           notes
                           )
                       VALUES(?,?,?,?,?,?,?)''',
                       (person_log.id,
                        person_id,
                        user_id,
                        person_log.date_log,
                        person_log.values,
                        person_log.action,
                        notes
                        )
                       )

    conn.commit()
    conn.close()

    print()
    print('--> person_log_count: ', person_log_count)

def clv_person_log_export_sqlite_10(client, args, db_path, table_name):

    conn = sqlite3.connect(db_path)
    conn.text_factory = str

    cursor = conn.cursor()
    try:
        cursor.execute('''DROP TABLE ''' + table_name + ''';''')
    except Exception as e:
        print('------->', e)
    cursor.execute('''
        CREATE TABLE ''' + table_name + ''' (
            id INTEGER NOT NULL PRIMARY KEY,
            person_id,
            user_id,
            date_log,
            values_,
            action,
            notes,
            new_id INTEGER
            );
    ''')

    # client.context = {'active_test': False}
    person_log = client.model('clv.person.log')
    person_log_browse = person_log.browse(args)

    person_log_count = 0
    for person_log in person_log_browse:
        person_log_count += 1

        print(
            person_log_count, person_log.id, person_log.values,
            person_log.date_log, person_log.notes
        )

        person_id = None
        if person_log.person_id:
            person_id = person_log.person_id.id

        user_id = None
        if person_log.user_id:
            user_id = person_log.user_id.id

        notes = None
        if person_log.notes:
            notes = person_log.notes

        cursor.execute('''
                       INSERT INTO ''' + table_name + '''(
                           id,
                           person_id,
                           user_id,
                           date_log,
                           values_,
                           action,
                           notes
                           )
                       VALUES(?,?,?,?,?,?,?)''',
                       (person_log.id,
                        person_id,
                        user_id,
                        person_log.date_log,
                        person_log.values,
                        person_log.action,
                        notes
                        )
                       )

    conn.commit()
    conn.close()

    print()
    print('--> person_log_count: ', person_log_count)

def clv_person_log_import_sqlite(client, args, db_path, table_name, person_table_name, res_users_table_name):

    person_log_model = client.model('clv.person.log')
    person_log_browse = person_log_model.browse([])
    person_log_browse.unlink()

    conn = sqlite3.connect(db_path)
    conn.row_factory = sqlite3.Row

    cursor = conn.cursor()

    cursor2 = conn.cursor()

    data = cursor.execute('''
        SELECT
            id,
            person_id,
            user_id,
            date_log,
            values_,
            action,
            notes,
            new_id
        FROM ''' + table_name + '''
        ORDER BY id;
    ''')

    print(data)
    print([field[0] for field in cursor.description])

    person_log_count = 0
    for row in cursor:
        person_log_count += 1

        print(
            person_log_count, row['id'], row['person_id'], row['user_id'], row['date_log'],
            row['values_'], row['action'], row['notes']
        )

        if row['person_id']:

            person_id = row['person_id']

            cursor2.execute(
                '''
                SELECT new_id
                FROM ''' + person_table_name + '''
                WHERE id = ?;''',
                (person_id,
                 )
            )
            person_id = cursor2.fetchone()[0]

        if row['user_id']:

            user_id = row['user_id']

            cursor2.execute(
                '''
                SELECT new_id
                FROM ''' + res_users_table_name + '''
                WHERE id = ?;''',
                (user_id,
                 )
            )
            user_id = cursor2.fetchone()[0]
            if user_id is None:
                user_id = 1

        values = {
            'person_id': person_id,
            'user_id': user_id,
            'date_log': row['date_log'],
            'values': row['values_'],
            'action': row['action'],
            'notes': row['notes'],
        }
        person_log_id = person_log_model.create(values).id

        cursor2.execute(
            '''
            UPDATE ''' + table_name + '''
            SET new_id = ?
            WHERE id = ?;''',
            (person_log_id,
             row['id']
             )
        )

    conn.commit()
    conn.close()

    print()
    print('--> person_log_count: ', person_log_count)
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import argparse
import glob
import os
import subprocess
import traceback
import xml.etree.ElementTree as ET

from collections import namedtuple
Replacement = namedtuple("Replacement", "offset length text")
Error = namedtuple("Error", "line column found expected")

__author__ = "github.com/cloderic"
__version__ = "0.2"

def replacements_from_file(file, style="file"):
    replacements = []

    clang_format_args = ["clang-format"]
    clang_format_args.append("-style={}".format(style))
    clang_format_args.append("-output-replacements-xml")
    clang_format_args.append(os.path.basename(file))
    replacement_xml = subprocess.check_output(clang_format_args,
                                              cwd=os.path.dirname(file))
    replacement_xml_root = ET.XML(replacement_xml)
    for replacement_item in replacement_xml_root.findall('replacement'):
        replacements.append(Replacement(
            offset=int(replacement_item.attrib["offset"]),
            length=int(replacement_item.attrib["length"]),
            text=replacement_item.text
        ))

    return replacements

def errors_from_replacements(file, replacements=[]):
    errors = []

    lines = [0]  # line index to character offset
    file_content = ""
    for line in open(file, "r"):
        file_content += line
        lines.append(lines[-1] + len(line))

    for line_index, line_offset in enumerate(lines[:-1]):
        while (len(replacements) > 0 and
               lines[line_index + 1] > replacements[0].offset):
            replacement = replacements.pop(0)
            errors.append(Error(
                line=line_index,
                column=replacement.offset - line_offset,
                found=file_content[replacement.offset:replacement.offset +
                                   replacement.length],
                expected=replacement.text if replacement.text else ""
            ))

        if len(replacements) == 0:
            break

    return errors

def clang_format_check(files=[], style="file"):
    error_count = 0
    file_errors = dict()

    for file in files:
        replacements = replacements_from_file(file, style)
        errors = errors_from_replacements(file, replacements)
        error_count += len(errors)
        file_errors[file] = errors
    return error_count, file_errors

def print_error_report(error_count, file_errors):
    if error_count == 0:
        print "No format error found"
    else:
        for file, errors in file_errors.iteritems():
            print "-- {} format errors at {}:".format(len(errors), file)
            for error in errors:
                print "    ({},{})".format(error.line + 1, error.column + 1)
                # print "        - found: \"{}\"".format(error.found)
                # print "        - expected: \"{}\"".format(error.expected)
        print "---"
        print "A total of {} format errors were found".format(error_count)

def check_clang_format_exec():
    try:
        subprocess.check_output(["clang-format", "-version"])
        return True
    except subprocess.CalledProcessError, e:
        # it seems that in some version of clang-format '-version' leads to
        # non-zero exist status
        return True
    except OSError, e:
        return False

def main():
    parser = argparse.ArgumentParser(
        description="C/C++ formatting check using clang-format")

    # Style
    parser.add_argument("-s", "--style",
                        default="file",
                        help="Coding style, pass-through to clang-format's "
                        "-style=<string>, (default is '%(default)s').")

    # Exit cleanly on missing clang-format
    parser.add_argument("--success-on-missing-clang-format",
                        action="store_true",
                        help="If set this flag will lead to a success (zero "
                        "exit status) if clang-format is not available.")

    # Files or directory to check
    parser.add_argument("file", nargs="+", help="Paths to the files that'll "
                        "be checked (wilcards accepted).")
    args = parser.parse_args()

    try:
        # Adding the double quotes around the inline style
        if len(args.style) > 0 and args.style[0] == "{":
            args.style = "\"" + args.style + "\""

        # Checking that clang-format is available
        if not check_clang_format_exec():
            print "Can't run 'clang-format', please make sure it is installed "
            "and reachable in your PATH."
            if args.success_on_missing_clang_format:
                exit(0)
            else:
                exit(-1)

        # globing the file paths
        files = set()
        for pattern in args.file:
            for file in glob.iglob(pattern):
                files.add(os.path.relpath(file))

        file_list = list(files)
        print "Checking {} files...".format(len(file_list))
        error_count, file_errors = clang_format_check(style=args.style,
                                                      files=file_list)
        print_error_report(error_count, file_errors)
        exit(error_count)

    except Exception, e:
        print "Exception raised:"
        print "    " + str(e)
        print '-'*60
        traceback.print_exc()
        print '-'*60
        exit(-2)

if __name__ == "__main__":
    main()
<commit_msg>Moving to 0.3 after some slight changes<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import argparse
import glob
import os
import subprocess
import traceback
import xml.etree.ElementTree as ET

from collections import namedtuple
Replacement = namedtuple("Replacement", "offset length text")
Error = namedtuple("Error", "line column found expected")

__author__ = "github.com/cloderic"
__version__ = "0.3"

def replacements_from_file(file, style="file"):
    replacements = []

    clang_format_args = ["clang-format"]
    clang_format_args.append("-style={}".format(style))
    clang_format_args.append("-output-replacements-xml")
    clang_format_args.append(os.path.basename(file))
    replacement_xml = subprocess.check_output(clang_format_args,
                                              cwd=os.path.dirname(file))
    replacement_xml_root = ET.XML(replacement_xml)
    for replacement_item in replacement_xml_root.findall('replacement'):
        replacements.append(Replacement(
            offset=int(replacement_item.attrib["offset"]),
            length=int(replacement_item.attrib["length"]),
            text=replacement_item.text
        ))

    return replacements

def errors_from_replacements(file, replacements=[]):
    errors = []

    lines = [0]  # line index to character offset
    file_content = ""
    for line in open(file, "r"):
        file_content += line
        lines.append(lines[-1] + len(line))

    for line_index, line_offset in enumerate(lines[:-1]):
        while (len(replacements) > 0 and
               lines[line_index + 1] > replacements[0].offset):
            replacement = replacements.pop(0)
            errors.append(Error(
                line=line_index,
                column=replacement.offset - line_offset,
                found=file_content[replacement.offset:replacement.offset +
                                   replacement.length],
                expected=replacement.text if replacement.text else ""
            ))

        if len(replacements) == 0:
            break

    return errors

def clang_format_check(files=[], style="file"):
    error_count = 0
    file_errors = dict()

    for file in files:
        replacements = replacements_from_file(file, style)
        errors = errors_from_replacements(file, replacements)
        error_count += len(errors)
        file_errors[file] = errors
    return error_count, file_errors

def print_error_report(error_count, file_errors):
    if error_count == 0:
        print "No format error found"
    else:
        for file, errors in file_errors.iteritems():
            print "-- {} format errors at {}:".format(len(errors), file)
            for error in errors:
                print "    ({},{})".format(error.line + 1, error.column + 1)
                # print "        - found: \"{}\"".format(error.found)
                # print "        - expected: \"{}\"".format(error.expected)
        print "---"
        print "A total of {} format errors were found".format(error_count)

def check_clang_format_exec():
    try:
        subprocess.check_output(["clang-format", "-version"])
        return True
    except subprocess.CalledProcessError, e:
        # it seems that in some version of clang-format '-version' leads to
        # non-zero exist status
        return True
    except OSError, e:
        return False

def main():
    parser = argparse.ArgumentParser(
        description="C/C++ formatting check using clang-format")

    # Style
    parser.add_argument("-s", "--style",
                        default="file",
                        help="Coding style, pass-through to clang-format's "
                        "-style=<string>, (default is '%(default)s').")

    # Exit cleanly on missing clang-format
    parser.add_argument("--success-on-missing-clang-format",
                        action="store_true",
                        help="If set this flag will lead to a success (zero "
                        "exit status) if clang-format is not available.")

    # Files or directory to check
    parser.add_argument("file", nargs="+", help="Paths to the files that'll "
                        "be checked (wilcards accepted).")
    args = parser.parse_args()

    try:
        # Adding the double quotes around the inline style
        if len(args.style) > 0 and args.style[0] == "{":
            args.style = "\"" + args.style + "\""

        # Checking that clang-format is available
        if not check_clang_format_exec():
            print "Can't run 'clang-format', please make sure it is installed "
            "and reachable in your PATH."
            if args.success_on_missing_clang_format:
                exit(0)
            else:
                exit(-1)

        # globing the file paths
        files = set()
        for pattern in args.file:
            for file in glob.iglob(pattern):
                files.add(os.path.relpath(file))

        file_list = list(files)
        print "Checking {} files...".format(len(file_list))
        error_count, file_errors = clang_format_check(style=args.style,
                                                      files=file_list)
        print_error_report(error_count, file_errors)
        exit(error_count)

    except Exception, e:
        print "Exception raised:"
        print "    " + str(e)
        print '-'*60
        traceback.print_exc()
        print '-'*60
        exit(-2)

if __name__ == "__main__":
    main()
<|endoftext|>


<commit_before>"""
Copyright 2009 Richard Quirk

Licensed 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.
"""
from __future__ import print_function
import sys
import re
import os
import getopt
import cmakelint.__version__

if sys.version_info < (3,):
    # xrange slightly faster than range on python2
    range = xrange

_RE_CLEAN_COMMENT = re.compile(r'(\s*\#.*)', re.VERBOSE)
_RE_COMMAND = re.compile(r'^\s*(\w+)(\s*)\(', re.VERBOSE)
_RE_COMMAND_START_SPACES = re.compile(r'^\s*\w+\s*\((\s*)', re.VERBOSE)
_RE_COMMAND_END_SPACES = re.compile(r'(\s*)\)', re.VERBOSE)
_RE_LOGIC_CHECK = re.compile(r'(\w+)\s*\(\s*\S+[^)]+\)', re.VERBOSE)
_RE_COMMAND_ARG = re.compile(r'(\w+)', re.VERBOSE)
_logic_commands = """
else
endforeach
endfunction
endif
endmacro
endwhile
""".split()
_USAGE = """
Syntax: cmakelint.py [--version] [--config=file] [--filter=-x,+y] [--spaces=N] <file> [file] ...
    filter=-x,+y,...
      Specify a comma separated list of filters to apply

    spaces=N
      Indentation should be a multiple of N spaces

    config=file
      Use the given file for configuration. By default the file
      ~/.cmakelintrc is used if it exists.  Use the value "None" to use no
      configuration file (./None for a file called literally None)
      Only the option "filter=" is currently supported in this file.

    version
      Show the version number and end
"""
_ERROR_CATEGORIES = """\
        convention/filename
        linelength
        package/consistency
        readability/logic
        readability/mixedcase
        readability/wonkycase
        syntax
        whitespace/eol
        whitespace/extra
        whitespace/indent
        whitespace/mismatch
        whitespace/newline
        whitespace/tabs
"""
_DEFAULT_CMAKELINTRC = os.path.join(os.path.expanduser('~'), '.cmakelintrc')

class _CMakeLintState(object):
    def __init__(self):
        self.filters = []
        self.config = 0
        self.errors = 0
        self.spaces = 2
        self.allowed_categories = _ERROR_CATEGORIES.split()

    def SetFilters(self, filters):
        if not filters:
            return
        if self.filters:
            self.filters.extend(filters.split(','))
        else:
            self.filters = filters.split(',')
        for f in self.filters:
            if f.startswith('-') or f.startswith('+'):
                allowed = False
                for c in self.allowed_categories:
                    if c.startswith(f[1:]):
                        allowed = True
                if not allowed:
                    raise ValueError('Filter not allowed: %s'%f)
            else:
                raise ValueError('Filter should start with - or +')

    def SetSpaces(self, spaces):
        self.spaces = int(spaces.strip())

class _CMakePackageState(object):
    def __init__(self):
        self.sets = []
        self.have_included_stdargs = False
        self.have_used_stdargs = False

    def Check(self, filename, linenumber, clean_lines, errors):
        pass

    def _GetExpected(self, filename):
        package = os.path.basename(filename)
        package = re.sub('^Find(.*)\.cmake', lambda m: m.group(1), package)
        return package.upper()

    def Done(self, filename, errors):
        try:
            if not IsFindPackage(filename):
                return
            if self.have_included_stdargs and self.have_used_stdargs:
                return
            if not self.have_included_stdargs:
                errors(
                    filename,
                    0,
                    'package/consistency',
                    'Package should include FindPackageHandleStandardArgs')
            if not self.have_used_stdargs:
                errors(
                    filename,
                    0,
                    'package/consistency',
                    'Package should use FIND_PACKAGE_HANDLE_STANDARD_ARGS')
        finally:
            self.have_used_stdargs = False
            self.have_included_stdargs = False

    def HaveUsedStandardArgs(self, filename, linenumber, var, errors):
        expected = self._GetExpected(filename)
        self.have_used_stdargs = True
        if expected != var:
            errors(
                filename,
                linenumber,
                'package/stdargs',
                'Weird variable passed to std args, should be ' +
                expected + ' not ' + var)

    def HaveIncluded(self, var):
        if var == 'FindPackageHandleStandardArgs':
            self.have_included_stdargs = True

    def Set(self, var):
        self.sets.append(var)

_lint_state = _CMakeLintState()
_package_state = _CMakePackageState()

def CleanComments(line):
    return _RE_CLEAN_COMMENT.sub('', line)

class CleansedLines(object):
    def __init__(self, lines):
        self.have_seen_uppercase = None
        self.raw_lines = lines
        self.lines = [CleanComments(line) for line in lines]

    def LineNumbers(self):
        return range(0, len(self.lines))

def ShouldPrintError(category):
    should_print = True
    for f in _lint_state.filters:
        if f.startswith('-') and category.startswith(f[1:]):
            should_print = False
        elif f.startswith('+') and category.startswith(f[1:]):
            should_print = True
    return should_print

def Error(filename, linenumber, category, message):
    if ShouldPrintError(category):
        _lint_state.errors += 1
        print('%s:%d: %s [%s]' % (filename, linenumber, message, category))

def CheckLineLength(filename, linenumber, clean_lines, errors):
    """
    Check for lines longer than the recommended length
    """
    line = clean_lines.raw_lines[linenumber]
    if len(line) > 80:
        return errors(
                filename,
                linenumber,
                'linelength',
                'Lines should be <= 80 characters long')

def ContainsCommand(line):
    return _RE_COMMAND.match(line)

def GetCommand(line):
    match = _RE_COMMAND.match(line)
    if match:
        return match.group(1)
    return ''

def IsCommandMixedCase(command):
    lower = command.lower()
    upper = command.upper()
    return not (command == lower or command == upper)

def IsCommandUpperCase(command):
    upper = command.upper()
    return command == upper

def CheckUpperLowerCase(filename, linenumber, clean_lines, errors):
    """
    Check that commands are either lower case or upper case, but not both
    """
    line = clean_lines.lines[linenumber]
    if ContainsCommand(line):
        command = GetCommand(line)
        if IsCommandMixedCase(command):
            return errors(
                    filename,
                    linenumber,
                    'readability/wonkycase',
                    'Do not use mixed case commands')
        if clean_lines.have_seen_uppercase is None:
            clean_lines.have_seen_uppercase = IsCommandUpperCase(command)
        else:
            is_upper = IsCommandUpperCase(command)
            if is_upper != clean_lines.have_seen_uppercase:
                return errors(
                        filename,
                        linenumber,
                        'readability/mixedcase',
                        'Do not mix upper and lower case commands')

def CheckCommandSpaces(filename, linenumber, clean_lines, errors):
    """
    No extra spaces between command and parenthesis
    """
    line = clean_lines.lines[linenumber]
    match = ContainsCommand(line)
    if match and len(match.group(2)):
        errors(filename, linenumber, 'whitespace/extra',
                "Extra spaces between '%s' and its ()"%(match.group(1)))
    if match:
        spaces_after_open = len(_RE_COMMAND_START_SPACES.match(line).group(1))
        initial_linenumber = linenumber
        end = None
        while True:
            line = clean_lines.lines[linenumber]
            end = _RE_COMMAND_END_SPACES.search(line)
            linenumber += 1
            if end or linenumber >= len(clean_lines.lines):
                break
        if linenumber == len(clean_lines.lines) and not end:
            errors(filename, initial_linenumber, 'syntax',
                    'Unable to find the end of this command')
        if end:
            spaces_before_end = len(end.group(1))
            if spaces_after_open != spaces_before_end:
                errors(filename, initial_linenumber, 'whitespace/mismatch',
                        'Mismatching spaces inside () after command')

def CheckRepeatLogic(filename, linenumber, clean_lines, errors):
    """
    Check for logic inside else, endif etc
    """
    line = clean_lines.lines[linenumber]
    for cmd in _logic_commands:
        if re.search(r'\b%s\b'%cmd, line.lower()):
            m = _RE_LOGIC_CHECK.search(line)
            if m:
                errors(filename, linenumber, 'readability/logic',
                        'Expression repeated inside %s; '
                        'better to use only %s()'%(cmd, m.group(1)))
            break

def CheckIndent(filename, linenumber, clean_lines, errors):
    initial_spaces = 0
    line = clean_lines.raw_lines[linenumber]
    while initial_spaces < len(line) and line[initial_spaces] == ' ':
        initial_spaces += 1
    remainder = initial_spaces % _lint_state.spaces
    if remainder != 0:
        errors(filename, linenumber, 'whitespace/indent',
                'Weird indentation; use %d spaces'%(_lint_state.spaces))

def CheckStyle(filename, linenumber, clean_lines, errors):
    """
    Check style issues. These are:
    No extra spaces between command and parenthesis
    Matching spaces between parenthesis and arguments
    No repeated logic in else(), endif(), endmacro()
    """
    CheckIndent(filename, linenumber, clean_lines, errors)
    CheckCommandSpaces(filename, linenumber, clean_lines, errors)
    line = clean_lines.raw_lines[linenumber]
    if line.find('\t') != -1:
        errors(filename, linenumber, 'whitespace/tabs', 'Tab found; please use spaces')

    if line and line[-1].isspace():
        errors(filename, linenumber, 'whitespace/eol', 'Line ends in whitespace')

    CheckRepeatLogic(filename, linenumber, clean_lines, errors)

def CheckFileName(filename, errors):
    name_match = re.match('Find(.*)\.cmake', os.path.basename(filename))
    if name_match:
        package = name_match.group(1)
        if not package.isupper():
            errors(filename, 0, 'convention/filename',
                    'Find modules should use uppercase names; '
                    'consider using Find' + package.upper() + '.cmake')
    else:
        if filename.lower() == 'cmakelists.txt' and filename != 'CMakeLists.txt':
            errors(filename, 0, 'convention/filename',
                    'File should be called CMakeLists.txt')

def IsFindPackage(filename):
    return os.path.basename(filename).startswith('Find') and filename.endswith('.cmake')

def GetCommandArgument(linenumber, clean_lines):
    line = clean_lines.lines[linenumber]
    skip = GetCommand(line)
    while True:
        line = clean_lines.lines[linenumber]
        m = _RE_COMMAND_ARG.finditer(line)
        for i in m:
            if i.group(1) == skip:
                continue
            return i.group(1)
        linenumber += 1
    return ''

def CheckFindPackage(filename, linenumber, clean_lines, errors):
    cmd = GetCommand(clean_lines.lines[linenumber])
    if cmd:
        if cmd.lower() == 'include':
            var_name = GetCommandArgument(linenumber, clean_lines)
            _package_state.HaveIncluded(var_name)
        elif cmd.lower() == 'find_package_handle_standard_args':
            var_name = GetCommandArgument(linenumber, clean_lines)
            _package_state.HaveUsedStandardArgs(filename, linenumber, var_name, errors)

def ProcessLine(filename, linenumber, clean_lines, errors):
    """
    Arguments:
      filename    the name of the file
      linenumber  the line number index
      clean_lines CleansedLines instance
      errors      the error handling function
    """
    CheckLineLength(filename, linenumber, clean_lines, errors)
    CheckUpperLowerCase(filename, linenumber, clean_lines, errors)
    CheckStyle(filename, linenumber, clean_lines, errors)
    if IsFindPackage(filename):
        CheckFindPackage(filename, linenumber, clean_lines, errors)

def IsValidFile(filename):
    return filename.endswith('.cmake') or os.path.basename(filename).lower() == 'cmakelists.txt'

def ProcessFile(filename):
    lines = ['# Lines start at 1']
    have_cr = False
    if not IsValidFile(filename):
        print('Ignoring file: ' + filename)
        return
    global _package_state
    _package_state = _CMakePackageState()
    CheckFileName(filename, Error)
    for l in open(filename).readlines():
        l = l.rstrip('\n')
        if l.endswith('\r'):
            have_cr = True
            l = l.rstrip('\r')
        lines.append(l)
    lines.append('# Lines end here')
    if have_cr and os.linesep != '\r\n':
        Error(filename, 0, 'whitespace/newline', 'Unexpected carriage return found; '
                'better to use only \\n')
    clean_lines = CleansedLines(lines)
    for line in clean_lines.LineNumbers():
        ProcessLine(filename, line, clean_lines, Error)
    _package_state.Done(filename, Error)

def PrintVersion():
    sys.stderr.write("cmakelint %s\n" % cmakelint.__version__.VERSION)
    sys.exit(0)

def PrintUsage(message):
    sys.stderr.write(_USAGE)
    if message:
        sys.exit('FATAL ERROR: '+message)
    else:
        sys.exit(1)

def PrintCategories():
    sys.stderr.write(_ERROR_CATEGORIES)
    sys.exit(0)

def ParseOptionFile(contents, ignore_space):
    filters = None
    spaces = None
    for line in contents:
        line = line.strip()
        if not line or line.startswith('#'):
            continue
        if line.startswith('filter='):
            filters = line.replace('filter=', '')
        if line.startswith('spaces='):
            spaces = line.replace('spaces=', '')
    _lint_state.SetFilters(filters)
    if spaces and not ignore_space:
        _lint_state.SetSpaces(spaces)

def ParseArgs(argv):
    try:
        (opts, filenames) = getopt.getopt(argv, '',
                ['help', 'filter=', 'config=', 'spaces=', 'version'])
    except getopt.GetoptError:
        PrintUsage('Invalid Arguments')
    filters = ""
    _lint_state.config = _DEFAULT_CMAKELINTRC
    ignore_space = False
    for (opt, val) in opts:
        if opt == '--version':
            PrintVersion()
        elif opt == '--help':
            PrintUsage(None)
        elif opt == '--filter':
            filters = val
            if not filters:
                PrintCategories()
        elif opt == '--config':
            _lint_state.config = val
            if _lint_state.config == 'None':
                _lint_state.config = None
        elif opt == '--spaces':
            try:
                _lint_state.SetSpaces(val)
                ignore_space = True
            except:
                PrintUsage('spaces expects an integer value')
    try:
        if _lint_state.config:
            try: ParseOptionFile(open(_lint_state.config, 'rU').readlines(), ignore_space)
            except IOError:
                pass
        _lint_state.SetFilters(filters)
    except ValueError as ex:
        PrintUsage(str(ex))

    if not filenames:
        PrintUsage('No files were specified!')
    return filenames

def main():
    files = ParseArgs(sys.argv[1:])

    for filename in files:
        ProcessFile(filename)
    sys.stderr.write("Total Errors: %d\n" % _lint_state.errors)
<commit_msg>improved the SetFilters function's implementation<commit_after>"""
Copyright 2009 Richard Quirk

Licensed 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.
"""
from __future__ import print_function
import sys
import re
import os
import getopt
import cmakelint.__version__

if sys.version_info < (3,):
    # xrange slightly faster than range on python2
    range = xrange

_RE_CLEAN_COMMENT = re.compile(r'(\s*\#.*)', re.VERBOSE)
_RE_COMMAND = re.compile(r'^\s*(\w+)(\s*)\(', re.VERBOSE)
_RE_COMMAND_START_SPACES = re.compile(r'^\s*\w+\s*\((\s*)', re.VERBOSE)
_RE_COMMAND_END_SPACES = re.compile(r'(\s*)\)', re.VERBOSE)
_RE_LOGIC_CHECK = re.compile(r'(\w+)\s*\(\s*\S+[^)]+\)', re.VERBOSE)
_RE_COMMAND_ARG = re.compile(r'(\w+)', re.VERBOSE)
_logic_commands = """
else
endforeach
endfunction
endif
endmacro
endwhile
""".split()
_USAGE = """
Syntax: cmakelint.py [--version] [--config=file] [--filter=-x,+y] [--spaces=N] <file> [file] ...
    filter=-x,+y,...
      Specify a comma separated list of filters to apply

    spaces=N
      Indentation should be a multiple of N spaces

    config=file
      Use the given file for configuration. By default the file
      ~/.cmakelintrc is used if it exists.  Use the value "None" to use no
      configuration file (./None for a file called literally None)
      Only the option "filter=" is currently supported in this file.

    version
      Show the version number and end
"""
_ERROR_CATEGORIES = """\
        convention/filename
        linelength
        package/consistency
        readability/logic
        readability/mixedcase
        readability/wonkycase
        syntax
        whitespace/eol
        whitespace/extra
        whitespace/indent
        whitespace/mismatch
        whitespace/newline
        whitespace/tabs
"""
_DEFAULT_CMAKELINTRC = os.path.join(os.path.expanduser('~'), '.cmakelintrc')

class _CMakeLintState(object):
    def __init__(self):
        self.filters = []
        self.config = 0
        self.errors = 0
        self.spaces = 2
        self.allowed_categories = _ERROR_CATEGORIES.split()

    def SetFilters(self, filters):
        if not filters:
            return
        assert isinstance(self.filters, list)
        if isinstance(filters, list):
            self.filters.extend(filters)
        elif isinstance(filters, str):
            self.filters.extend([f.strip() for f in filters.split(',') if f])
        else:
            raise ValueError('Filters should be a list or a comma separated string')
        for f in self.filters:
            if f.startswith('-') or f.startswith('+'):
                allowed = False
                for c in self.allowed_categories:
                    if c.startswith(f[1:]):
                        allowed = True
                if not allowed:
                    raise ValueError('Filter not allowed: %s'%f)
            else:
                raise ValueError('Filter should start with - or +')

    def SetSpaces(self, spaces):
        self.spaces = int(spaces.strip())

class _CMakePackageState(object):
    def __init__(self):
        self.sets = []
        self.have_included_stdargs = False
        self.have_used_stdargs = False

    def Check(self, filename, linenumber, clean_lines, errors):
        pass

    def _GetExpected(self, filename):
        package = os.path.basename(filename)
        package = re.sub('^Find(.*)\.cmake', lambda m: m.group(1), package)
        return package.upper()

    def Done(self, filename, errors):
        try:
            if not IsFindPackage(filename):
                return
            if self.have_included_stdargs and self.have_used_stdargs:
                return
            if not self.have_included_stdargs:
                errors(
                    filename,
                    0,
                    'package/consistency',
                    'Package should include FindPackageHandleStandardArgs')
            if not self.have_used_stdargs:
                errors(
                    filename,
                    0,
                    'package/consistency',
                    'Package should use FIND_PACKAGE_HANDLE_STANDARD_ARGS')
        finally:
            self.have_used_stdargs = False
            self.have_included_stdargs = False

    def HaveUsedStandardArgs(self, filename, linenumber, var, errors):
        expected = self._GetExpected(filename)
        self.have_used_stdargs = True
        if expected != var:
            errors(
                filename,
                linenumber,
                'package/stdargs',
                'Weird variable passed to std args, should be ' +
                expected + ' not ' + var)

    def HaveIncluded(self, var):
        if var == 'FindPackageHandleStandardArgs':
            self.have_included_stdargs = True

    def Set(self, var):
        self.sets.append(var)

_lint_state = _CMakeLintState()
_package_state = _CMakePackageState()

def CleanComments(line):
    return _RE_CLEAN_COMMENT.sub('', line)

class CleansedLines(object):
    def __init__(self, lines):
        self.have_seen_uppercase = None
        self.raw_lines = lines
        self.lines = [CleanComments(line) for line in lines]

    def LineNumbers(self):
        return range(0, len(self.lines))

def ShouldPrintError(category):
    should_print = True
    for f in _lint_state.filters:
        if f.startswith('-') and category.startswith(f[1:]):
            should_print = False
        elif f.startswith('+') and category.startswith(f[1:]):
            should_print = True
    return should_print

def Error(filename, linenumber, category, message):
    if ShouldPrintError(category):
        _lint_state.errors += 1
        print('%s:%d: %s [%s]' % (filename, linenumber, message, category))

def CheckLineLength(filename, linenumber, clean_lines, errors):
    """
    Check for lines longer than the recommended length
    """
    line = clean_lines.raw_lines[linenumber]
    if len(line) > 80:
        return errors(
                filename,
                linenumber,
                'linelength',
                'Lines should be <= 80 characters long')

def ContainsCommand(line):
    return _RE_COMMAND.match(line)

def GetCommand(line):
    match = _RE_COMMAND.match(line)
    if match:
        return match.group(1)
    return ''

def IsCommandMixedCase(command):
    lower = command.lower()
    upper = command.upper()
    return not (command == lower or command == upper)

def IsCommandUpperCase(command):
    upper = command.upper()
    return command == upper

def CheckUpperLowerCase(filename, linenumber, clean_lines, errors):
    """
    Check that commands are either lower case or upper case, but not both
    """
    line = clean_lines.lines[linenumber]
    if ContainsCommand(line):
        command = GetCommand(line)
        if IsCommandMixedCase(command):
            return errors(
                    filename,
                    linenumber,
                    'readability/wonkycase',
                    'Do not use mixed case commands')
        if clean_lines.have_seen_uppercase is None:
            clean_lines.have_seen_uppercase = IsCommandUpperCase(command)
        else:
            is_upper = IsCommandUpperCase(command)
            if is_upper != clean_lines.have_seen_uppercase:
                return errors(
                        filename,
                        linenumber,
                        'readability/mixedcase',
                        'Do not mix upper and lower case commands')

def CheckCommandSpaces(filename, linenumber, clean_lines, errors):
    """
    No extra spaces between command and parenthesis
    """
    line = clean_lines.lines[linenumber]
    match = ContainsCommand(line)
    if match and len(match.group(2)):
        errors(filename, linenumber, 'whitespace/extra',
                "Extra spaces between '%s' and its ()"%(match.group(1)))
    if match:
        spaces_after_open = len(_RE_COMMAND_START_SPACES.match(line).group(1))
        initial_linenumber = linenumber
        end = None
        while True:
            line = clean_lines.lines[linenumber]
            end = _RE_COMMAND_END_SPACES.search(line)
            linenumber += 1
            if end or linenumber >= len(clean_lines.lines):
                break
        if linenumber == len(clean_lines.lines) and not end:
            errors(filename, initial_linenumber, 'syntax',
                    'Unable to find the end of this command')
        if end:
            spaces_before_end = len(end.group(1))
            if spaces_after_open != spaces_before_end:
                errors(filename, initial_linenumber, 'whitespace/mismatch',
                        'Mismatching spaces inside () after command')

def CheckRepeatLogic(filename, linenumber, clean_lines, errors):
    """
    Check for logic inside else, endif etc
    """
    line = clean_lines.lines[linenumber]
    for cmd in _logic_commands:
        if re.search(r'\b%s\b'%cmd, line.lower()):
            m = _RE_LOGIC_CHECK.search(line)
            if m:
                errors(filename, linenumber, 'readability/logic',
                        'Expression repeated inside %s; '
                        'better to use only %s()'%(cmd, m.group(1)))
            break

def CheckIndent(filename, linenumber, clean_lines, errors):
    initial_spaces = 0
    line = clean_lines.raw_lines[linenumber]
    while initial_spaces < len(line) and line[initial_spaces] == ' ':
        initial_spaces += 1
    remainder = initial_spaces % _lint_state.spaces
    if remainder != 0:
        errors(filename, linenumber, 'whitespace/indent',
                'Weird indentation; use %d spaces'%(_lint_state.spaces))

def CheckStyle(filename, linenumber, clean_lines, errors):
    """
    Check style issues. These are:
    No extra spaces between command and parenthesis
    Matching spaces between parenthesis and arguments
    No repeated logic in else(), endif(), endmacro()
    """
    CheckIndent(filename, linenumber, clean_lines, errors)
    CheckCommandSpaces(filename, linenumber, clean_lines, errors)
    line = clean_lines.raw_lines[linenumber]
    if line.find('\t') != -1:
        errors(filename, linenumber, 'whitespace/tabs', 'Tab found; please use spaces')

    if line and line[-1].isspace():
        errors(filename, linenumber, 'whitespace/eol', 'Line ends in whitespace')

    CheckRepeatLogic(filename, linenumber, clean_lines, errors)

def CheckFileName(filename, errors):
    name_match = re.match('Find(.*)\.cmake', os.path.basename(filename))
    if name_match:
        package = name_match.group(1)
        if not package.isupper():
            errors(filename, 0, 'convention/filename',
                    'Find modules should use uppercase names; '
                    'consider using Find' + package.upper() + '.cmake')
    else:
        if filename.lower() == 'cmakelists.txt' and filename != 'CMakeLists.txt':
            errors(filename, 0, 'convention/filename',
                    'File should be called CMakeLists.txt')

def IsFindPackage(filename):
    return os.path.basename(filename).startswith('Find') and filename.endswith('.cmake')

def GetCommandArgument(linenumber, clean_lines):
    line = clean_lines.lines[linenumber]
    skip = GetCommand(line)
    while True:
        line = clean_lines.lines[linenumber]
        m = _RE_COMMAND_ARG.finditer(line)
        for i in m:
            if i.group(1) == skip:
                continue
            return i.group(1)
        linenumber += 1
    return ''

def CheckFindPackage(filename, linenumber, clean_lines, errors):
    cmd = GetCommand(clean_lines.lines[linenumber])
    if cmd:
        if cmd.lower() == 'include':
            var_name = GetCommandArgument(linenumber, clean_lines)
            _package_state.HaveIncluded(var_name)
        elif cmd.lower() == 'find_package_handle_standard_args':
            var_name = GetCommandArgument(linenumber, clean_lines)
            _package_state.HaveUsedStandardArgs(filename, linenumber, var_name, errors)

def ProcessLine(filename, linenumber, clean_lines, errors):
    """
    Arguments:
      filename    the name of the file
      linenumber  the line number index
      clean_lines CleansedLines instance
      errors      the error handling function
    """
    CheckLineLength(filename, linenumber, clean_lines, errors)
    CheckUpperLowerCase(filename, linenumber, clean_lines, errors)
    CheckStyle(filename, linenumber, clean_lines, errors)
    if IsFindPackage(filename):
        CheckFindPackage(filename, linenumber, clean_lines, errors)

def IsValidFile(filename):
    return filename.endswith('.cmake') or os.path.basename(filename).lower() == 'cmakelists.txt'

def ProcessFile(filename):
    lines = ['# Lines start at 1']
    have_cr = False
    if not IsValidFile(filename):
        print('Ignoring file: ' + filename)
        return
    global _package_state
    _package_state = _CMakePackageState()
    CheckFileName(filename, Error)
    for l in open(filename).readlines():
        l = l.rstrip('\n')
        if l.endswith('\r'):
            have_cr = True
            l = l.rstrip('\r')
        lines.append(l)
    lines.append('# Lines end here')
    if have_cr and os.linesep != '\r\n':
        Error(filename, 0, 'whitespace/newline', 'Unexpected carriage return found; '
                'better to use only \\n')
    clean_lines = CleansedLines(lines)
    for line in clean_lines.LineNumbers():
        ProcessLine(filename, line, clean_lines, Error)
    _package_state.Done(filename, Error)

def PrintVersion():
    sys.stderr.write("cmakelint %s\n" % cmakelint.__version__.VERSION)
    sys.exit(0)

def PrintUsage(message):
    sys.stderr.write(_USAGE)
    if message:
        sys.exit('FATAL ERROR: '+message)
    else:
        sys.exit(1)

def PrintCategories():
    sys.stderr.write(_ERROR_CATEGORIES)
    sys.exit(0)

def ParseOptionFile(contents, ignore_space):
    filters = None
    spaces = None
    for line in contents:
        line = line.strip()
        if not line or line.startswith('#'):
            continue
        if line.startswith('filter='):
            filters = line.replace('filter=', '')
        if line.startswith('spaces='):
            spaces = line.replace('spaces=', '')
    _lint_state.SetFilters(filters)
    if spaces and not ignore_space:
        _lint_state.SetSpaces(spaces)

def ParseArgs(argv):
    try:
        (opts, filenames) = getopt.getopt(argv, '',
                ['help', 'filter=', 'config=', 'spaces=', 'version'])
    except getopt.GetoptError:
        PrintUsage('Invalid Arguments')
    filters = ""
    _lint_state.config = _DEFAULT_CMAKELINTRC
    ignore_space = False
    for (opt, val) in opts:
        if opt == '--version':
            PrintVersion()
        elif opt == '--help':
            PrintUsage(None)
        elif opt == '--filter':
            filters = val
            if not filters:
                PrintCategories()
        elif opt == '--config':
            _lint_state.config = val
            if _lint_state.config == 'None':
                _lint_state.config = None
        elif opt == '--spaces':
            try:
                _lint_state.SetSpaces(val)
                ignore_space = True
            except:
                PrintUsage('spaces expects an integer value')
    try:
        if _lint_state.config:
            try: ParseOptionFile(open(_lint_state.config, 'rU').readlines(), ignore_space)
            except IOError:
                pass
        _lint_state.SetFilters(filters)
    except ValueError as ex:
        PrintUsage(str(ex))

    if not filenames:
        PrintUsage('No files were specified!')
    return filenames

def main():
    files = ParseArgs(sys.argv[1:])

    for filename in files:
        ProcessFile(filename)
    sys.stderr.write("Total Errors: %d\n" % _lint_state.errors)
<|endoftext|>