<commit_before># -*- encoding: utf-8 -*-

# Dissemin: open access policy enforcement tool
# Copyright (C) 2014 Antonin Delpeuch
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#

import allauth.account.views
import django_js_reverse.views

from allauth.socialaccount import providers

from django.conf import settings
from django.urls import include
from django.urls import path
from django.urls import re_path
from django.conf.urls.static import static
from django.contrib import admin
from django.contrib.auth import logout
from django.shortcuts import redirect
from django.shortcuts import render
from django.views import generic
from django.views.generic.base import TemplateView
from django.views.i18n import JavaScriptCatalog

from dissemin.views import LoginView
from dissemin.views import StartPageView
from papers.ajax import claimPaper
from papers.ajax import unclaimPaper
from papers.ajax import todo_list_add
from papers.ajax import todo_list_remove
from papers.views import AdvancedPaperSearchView
from papers.views import MyProfileView
from papers.views import MyTodoListView
from papers.views import PaperSearchView
from papers.views import ResearcherView
from papers.views import refetch_researcher
from publishers.ajax import change_publisher_status
from publishers.views import PublisherView
from publishers.views import PublishersView

try:
    import importlib
except ImportError:
    from django.utils import importlib

def handler404(request, exception=None):
    response = render(request, '403.html', {'exception':exception})
    response.status_code = 404
    return response

def handler404(request, exception=None):
    response = render(request, '404.html', {'exception':exception})
    response.status_code = 404
    return response

def handler500(request, exception=None):
    response = render(request, '500.html', {'exception':exception})
    response.status_code = 500
    return response

def logoutView(request):
    logout(request)
    if 'HTTP_REFERER' in request.META:
        return redirect(request.META['HTTP_REFERER'])
    else:
        return redirect('/')

js_info_dict = {
    'packages': (
        'dissemin'
    )
}

urlpatterns = [
    # Start page
    path('', StartPageView.as_view(), name='start-page'),
    # Paper related pages
    path('search/', PaperSearchView.as_view(), name='search'),
    path('advanced-search/', AdvancedPaperSearchView.as_view(), name='advanced-search'),
    # Publisher related pages
    path('publishers/', PublishersView.as_view(), name='publishers'),
    path('b/<int:pk>/<slug:slug>/', PublisherView.as_view(), name='publisher'),
    # Researcher realted pages
    path('r/<int:researcher>/<slug:slug>/', ResearcherView.as_view(), name='researcher'),
    re_path(r'^(?P<orcid>[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[X0-9])/$', ResearcherView.as_view(), name='researcher-by-orcid'),
    # User related pages
    path('my-profile/', MyProfileView.as_view(), name='my-profile'),
    path('my-todolist/', MyTodoListView.as_view(), name='my-todolist'),
    # Static pages
    path('faq/', TemplateView.as_view(template_name='dissemin/faq.html'), name='faq'),
    path('sources/', TemplateView.as_view(template_name='dissemin/sources.html'), name='sources'),
    path('tos/', TemplateView.as_view(template_name='dissemin/tos.html'), name='tos'),
    # AJAX
    path('ajax/change_publisher_status/', change_publisher_status, name='ajax_change_publisher_status'),
    path('ajax/claim-paper/', claimPaper, name='ajax-claimPaper'),
    path('ajax/unclaim-paper/', unclaimPaper, name='ajax-unclaimPaper'),
    path('ajax/researcher/<int:pk>/update/', refetch_researcher, name='refetch-researcher'),
    path('ajax/todolist-add/', todo_list_add, name='ajax-todolist-add'),
    path('ajax/todolist-remove/', todo_list_remove, name='ajax-todolist-remove'),
    path('faq', TemplateView.as_view(template_name='dissemin/faq.html'), name='faq'),
    path('sources', TemplateView.as_view(template_name='dissemin/sources.html'), name='sources'),
    path('tos', TemplateView.as_view(template_name='dissemin/tos.html'), name='tos'),
    # Admin interface
    path('admin/', admin.site.urls),
    # Apps
    path('ajax-upload/', include('upload.urls')),
    path('', include('papers.urls')),
    path('', include('publishers.urls')),
    path('', include('deposit.urls')),
    path('', include('notification.urls')),
    path('', include('autocomplete.urls')),
    path('jsreverse/', django_js_reverse.views.urls_js, name='js_reverse'),
    # Social auth
    path('accounts/login/', LoginView.as_view(), name='account-login'),
    path('accounts/logout/', logoutView, name='account-logout'),
    path('accounts/social/', include('allauth.socialaccount.urls')),
    # JavaScript i18n
    path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'),
    path('lang/', include('django.conf.urls.i18n'), name='set_language'),
    # Remove this in production
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT
           ) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

# Allauth social providers (normally included directly in the standard installation
# of django-allauth, but as we disabled normal auth, we have to do it here).
for provider in providers.registry.get_list():
    try:
        prov_mod = importlib.import_module(provider.get_package() + '.urls')
    except ImportError:
        continue
    prov_urlpatterns = getattr(prov_mod, 'urlpatterns', None)
    if prov_urlpatterns:
        urlpatterns += prov_urlpatterns

# Debug toolbar
if 'debug_toolbar' in settings.INSTALLED_APPS:
    import debug_toolbar
    urlpatterns.append(
      path('__debug__/', include(debug_toolbar.urls)))

<commit_msg>publisher urls no longer exist<commit_after># -*- encoding: utf-8 -*-

# Dissemin: open access policy enforcement tool
# Copyright (C) 2014 Antonin Delpeuch
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#

import allauth.account.views
import django_js_reverse.views

from allauth.socialaccount import providers

from django.conf import settings
from django.urls import include
from django.urls import path
from django.urls import re_path
from django.conf.urls.static import static
from django.contrib import admin
from django.contrib.auth import logout
from django.shortcuts import redirect
from django.shortcuts import render
from django.views import generic
from django.views.generic.base import TemplateView
from django.views.i18n import JavaScriptCatalog

from dissemin.views import LoginView
from dissemin.views import StartPageView
from papers.ajax import claimPaper
from papers.ajax import unclaimPaper
from papers.ajax import todo_list_add
from papers.ajax import todo_list_remove
from papers.views import AdvancedPaperSearchView
from papers.views import MyProfileView
from papers.views import MyTodoListView
from papers.views import PaperSearchView
from papers.views import ResearcherView
from papers.views import refetch_researcher
from publishers.ajax import change_publisher_status
from publishers.views import PublisherView
from publishers.views import PublishersView

try:
    import importlib
except ImportError:
    from django.utils import importlib

def handler404(request, exception=None):
    response = render(request, '403.html', {'exception':exception})
    response.status_code = 404
    return response

def handler404(request, exception=None):
    response = render(request, '404.html', {'exception':exception})
    response.status_code = 404
    return response

def handler500(request, exception=None):
    response = render(request, '500.html', {'exception':exception})
    response.status_code = 500
    return response

def logoutView(request):
    logout(request)
    if 'HTTP_REFERER' in request.META:
        return redirect(request.META['HTTP_REFERER'])
    else:
        return redirect('/')

js_info_dict = {
    'packages': (
        'dissemin'
    )
}

urlpatterns = [
    # Start page
    path('', StartPageView.as_view(), name='start-page'),
    # Paper related pages
    path('search/', PaperSearchView.as_view(), name='search'),
    path('advanced-search/', AdvancedPaperSearchView.as_view(), name='advanced-search'),
    # Publisher related pages
    path('publishers/', PublishersView.as_view(), name='publishers'),
    path('b/<int:pk>/<slug:slug>/', PublisherView.as_view(), name='publisher'),
    # Researcher realted pages
    path('r/<int:researcher>/<slug:slug>/', ResearcherView.as_view(), name='researcher'),
    re_path(r'^(?P<orcid>[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[X0-9])/$', ResearcherView.as_view(), name='researcher-by-orcid'),
    # User related pages
    path('my-profile/', MyProfileView.as_view(), name='my-profile'),
    path('my-todolist/', MyTodoListView.as_view(), name='my-todolist'),
    # Static pages
    path('faq/', TemplateView.as_view(template_name='dissemin/faq.html'), name='faq'),
    path('sources/', TemplateView.as_view(template_name='dissemin/sources.html'), name='sources'),
    path('tos/', TemplateView.as_view(template_name='dissemin/tos.html'), name='tos'),
    # AJAX
    path('ajax/change_publisher_status/', change_publisher_status, name='ajax_change_publisher_status'),
    path('ajax/claim-paper/', claimPaper, name='ajax-claimPaper'),
    path('ajax/unclaim-paper/', unclaimPaper, name='ajax-unclaimPaper'),
    path('ajax/researcher/<int:pk>/update/', refetch_researcher, name='refetch-researcher'),
    path('ajax/todolist-add/', todo_list_add, name='ajax-todolist-add'),
    path('ajax/todolist-remove/', todo_list_remove, name='ajax-todolist-remove'),
    path('faq', TemplateView.as_view(template_name='dissemin/faq.html'), name='faq'),
    path('sources', TemplateView.as_view(template_name='dissemin/sources.html'), name='sources'),
    path('tos', TemplateView.as_view(template_name='dissemin/tos.html'), name='tos'),
    # Admin interface
    path('admin/', admin.site.urls),
    # Apps
    path('ajax-upload/', include('upload.urls')),
    path('', include('papers.urls')),
    path('', include('deposit.urls')),
    path('', include('notification.urls')),
    path('', include('autocomplete.urls')),
    path('jsreverse/', django_js_reverse.views.urls_js, name='js_reverse'),
    # Social auth
    path('accounts/login/', LoginView.as_view(), name='account-login'),
    path('accounts/logout/', logoutView, name='account-logout'),
    path('accounts/social/', include('allauth.socialaccount.urls')),
    # JavaScript i18n
    path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'),
    path('lang/', include('django.conf.urls.i18n'), name='set_language'),
    # Remove this in production
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT
           ) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

# Allauth social providers (normally included directly in the standard installation
# of django-allauth, but as we disabled normal auth, we have to do it here).
for provider in providers.registry.get_list():
    try:
        prov_mod = importlib.import_module(provider.get_package() + '.urls')
    except ImportError:
        continue
    prov_urlpatterns = getattr(prov_mod, 'urlpatterns', None)
    if prov_urlpatterns:
        urlpatterns += prov_urlpatterns

# Debug toolbar
if 'debug_toolbar' in settings.INSTALLED_APPS:
    import debug_toolbar
    urlpatterns.append(
      path('__debug__/', include(debug_toolbar.urls)))

<|endoftext|>


<commit_before>import ply.lex
import oelite.parse.bbparse

bblexer = None

__initialized__ = False
if not __initialized__:
    import bblex
    bblexer = ply.lex.lex(module=bblex)
    __initialized__ = True

class ExpandError(Exception):
    def __init__(self, parser, msg):
        self.parser = parser
        self.msg = msg
        return

    def __repr__(self):
        return "ExpandError(%s)"%(repr(self.msg))

    def __str__(self):
        return "Variable expansion error: %s"%(self.msg)

class ParseError(Exception):

    def __init__(self, parser, msg, details=None, symbol=None, lineno=None,
                 more_details=None):
        """
        parser = BBParser instance
        msg = string
        details =
        """
        assert isinstance(parser, oelite.parse.bbparse.BBParser)
        assert isinstance(msg, basestring)

        self.parser = parser
        self.msg = msg
        self.more_details = more_details
        try:
            self.lexer = details.lexer
        except:
            self.lexer = parser.lexer
        #print "parser=%s"%(parser)
        #print dir(self.parser)
        #print dir(self.parser.lexer)
        #print "lineno arg", lineno
        #print "lineno", self.parser.lexer.lineno
        if not self.parser and "parser" in dir(self.lexer):
        #if not self.parser:
            self.parser = self.lexer.parser
        if details:
            self.details = details
        elif "yacc" in dir(self.parser) and "lexer" in dir(self.parser.yacc):
            self.details = self.parser.yacc.lexer
        elif self.parser and "lexer" in dir(self.parser):
            self.details = self.parser.lexer
        else:
            self.details = None
        if lineno is not None:
            self.errlineno = lineno
        elif "lexer" in dir(self.parser) and "lineno" in dir(self.parser.lexer):
            self.errlineno = self.parser.lexer.lineno
        elif "details" in self and "lexer" in dir(self.details):
            self.errlineno = self.details.lexer.lineno
        elif "details" in self and "lineno" in dir(self.details):
            self.errlineno = self.details.lineno
        else:
            # FIXME: try harder to get a proper errlineno
            self.errlineno = 0
        if symbol:
            self.symbol = symbol
        #elif self.details is None:
        #    self.symbol = ""
        elif not "value" in dir(self.details):
            self.symbol = None
        elif self.details.type == "error":
            self.symbol = self.details.value[0]
        else:
            self.symbol = self.details.value
        if self.symbol and self.symbol.endswith("\n"):
            # FIXME: is this always correct?
            self.errlineno -= 1
        if "filename" in dir(self.parser):
            self.filename = self.parser.filename
        elif not self.filename:
            self.filename = "<unknown file>",
        #if isinstance(self.parser, oelite.parse.bbparse.BBParser):
        #    self.parser = parser.yacc
        if not self.symbol:
            self.msg += " in %s at line %d"%(
                self.filename, self.errlineno + 1)
        elif self.details.type == "error":
            self.msg += " in %s at line %d: %s"%(
                self.filename, self.errlineno + 1,
                repr(self.symbol))
        else:
            self.msg += " in %s at line %d: %s %s"%(
                self.filename, self.errlineno + 1,
                self.details.type, repr(self.symbol))
        return

    def __str__(self):
        return self.msg

    def print_details(self):
        print self.msg
        if not self.details:
            return ""
        if "text" in dir(self.parser):
            lines = self.parser.text.splitlines()
        elif "yacc" in dir(self.parser) and "text" in dir(self.parser.yacc):
            lines = self.parser.yacc.text.splitlines()
        else:
            print type(self.lexer.lexdata)
            lines = self.lexer.lexdata.splitlines()
        #errlineno = self.details.lineno
        #errlineno = self.lexer.lineno
        firstline = max(self.errlineno - 5, 0)
        lastline = min(self.errlineno + 5, len(lines))
        errlinepos = 0
        for lineno in xrange(self.errlineno):
            errlinepos += len(lines[lineno]) + 1
        #if isinstance(self.details, ply.lex.LexToken):
        #    print "this is a LexToken"
        #    lexpos = self.details.lexpos
        #elif isinstance(self.details, ply.lex.Lexer):
        #    print "this is a Lexer"
        #    lexpos = self.details.lexpos - len(self.symbol)
        try:
            #lexpos = self.details.lexpos
            lexpos = self.lexer.lexpos
            errpos = (lexpos - 1) - errlinepos
            errlinebefore = lines[self.errlineno]\
                [:(lexpos - errlinepos)]
            errlinebefore = len(errlinebefore.expandtabs())
        except AttributeError:
            lexpos = None
        linenofmtlen = len(str(lastline))
        lineprintfmt = "%%s%%%dd %%s"%(linenofmtlen)
        for lineno in xrange(firstline, lastline):
            if lineno == self.errlineno:
                #print ""
                prefix = "-> "
            else:
                prefix = "   "
            print lineprintfmt%(prefix, lineno + 1,
                                lines[lineno].expandtabs())
            if lineno == self.errlineno:
                if lexpos:
                    prefixlen = len(prefix) + linenofmtlen + 1
                    print "%s%s"%(" "*(prefixlen + errlinebefore),
                                  "^"*len(self.symbol or ""))
                else:
                    print ""
        if self.parser.parent:
            parent = self.parser.parent
            print "Included from %s"%(parent.filename)
            parent = parent.parent
            while parent:
                print "              %s"%(parent.filename)
                parent = parent.parent
        if self.more_details:
            if "print_details" in dir(self.more_details):
                self.more_details.print_details()
            else:
                print self.more_details
        return

class StatementNotAllowed(ParseError):

    def __init(self, parser, p, statement):
        super(StatementNotAllowedInConf, self).__init__(
            parser, "%s statement not allowed"%(statement), p)
        return

class FileNotFound(ParseError):

    def __init__(self, parser, filename, p, lineno=None):
        self.filename = filename
        super(FileNotFound, self).__init__(
            parser, "%s not found"%(filename), p, lineno=lineno)
        return

__all__ = [
    "bblex", "bbparse", "confparse",
    "ParseError", "StatementNotAllowed", "FileNotFound",
    "bblexer",
    ]

import bblex
import bbparse
import confparse
<commit_msg>lib/oelite: Fix error messages when parsing non-string symbols<commit_after>import ply.lex
import oelite.parse.bbparse

bblexer = None

__initialized__ = False
if not __initialized__:
    import bblex
    bblexer = ply.lex.lex(module=bblex)
    __initialized__ = True

class ExpandError(Exception):
    def __init__(self, parser, msg):
        self.parser = parser
        self.msg = msg
        return

    def __repr__(self):
        return "ExpandError(%s)"%(repr(self.msg))

    def __str__(self):
        return "Variable expansion error: %s"%(self.msg)

class ParseError(Exception):

    def __init__(self, parser, msg, details=None, symbol=None, lineno=None,
                 more_details=None):
        """
        parser = BBParser instance
        msg = string
        details =
        """
        assert isinstance(parser, oelite.parse.bbparse.BBParser)
        assert isinstance(msg, basestring)

        self.parser = parser
        self.msg = msg
        self.more_details = more_details
        try:
            self.lexer = details.lexer
        except:
            self.lexer = parser.lexer
        #print "parser=%s"%(parser)
        #print dir(self.parser)
        #print dir(self.parser.lexer)
        #print "lineno arg", lineno
        #print "lineno", self.parser.lexer.lineno
        if not self.parser and "parser" in dir(self.lexer):
        #if not self.parser:
            self.parser = self.lexer.parser
        if details:
            self.details = details
        elif "yacc" in dir(self.parser) and "lexer" in dir(self.parser.yacc):
            self.details = self.parser.yacc.lexer
        elif self.parser and "lexer" in dir(self.parser):
            self.details = self.parser.lexer
        else:
            self.details = None
        if lineno is not None:
            self.errlineno = lineno
        elif "lexer" in dir(self.parser) and "lineno" in dir(self.parser.lexer):
            self.errlineno = self.parser.lexer.lineno
        elif "details" in self and "lexer" in dir(self.details):
            self.errlineno = self.details.lexer.lineno
        elif "details" in self and "lineno" in dir(self.details):
            self.errlineno = self.details.lineno
        else:
            # FIXME: try harder to get a proper errlineno
            self.errlineno = 0
        if symbol:
            self.symbol = symbol
        #elif self.details is None:
        #    self.symbol = ""
        elif not "value" in dir(self.details):
            self.symbol = None
        elif self.details.type == "error":
            self.symbol = self.details.value[0]
        else:
            self.symbol = self.details.value
        if isinstance(self.symbol, basestring) and self.symbol.endswith("\n"):
            # FIXME: is this always correct?
            self.errlineno -= 1
        if "filename" in dir(self.parser):
            self.filename = self.parser.filename
        elif not self.filename:
            self.filename = "<unknown file>",
        #if isinstance(self.parser, oelite.parse.bbparse.BBParser):
        #    self.parser = parser.yacc
        if not self.symbol:
            self.msg += " in %s at line %d"%(
                self.filename, self.errlineno + 1)
        elif self.details.type == "error":
            self.msg += " in %s at line %d: %s"%(
                self.filename, self.errlineno + 1,
                repr(self.symbol))
        else:
            self.msg += " in %s at line %d: %s %s"%(
                self.filename, self.errlineno + 1,
                self.details.type, repr(self.symbol))
        return

    def __str__(self):
        return self.msg

    def print_details(self):
        print self.msg
        if not self.details:
            return ""
        if "text" in dir(self.parser):
            lines = self.parser.text.splitlines()
        elif "yacc" in dir(self.parser) and "text" in dir(self.parser.yacc):
            lines = self.parser.yacc.text.splitlines()
        else:
            print type(self.lexer.lexdata)
            lines = self.lexer.lexdata.splitlines()
        #errlineno = self.details.lineno
        #errlineno = self.lexer.lineno
        firstline = max(self.errlineno - 5, 0)
        lastline = min(self.errlineno + 5, len(lines))
        errlinepos = 0
        for lineno in xrange(self.errlineno):
            errlinepos += len(lines[lineno]) + 1
        #if isinstance(self.details, ply.lex.LexToken):
        #    print "this is a LexToken"
        #    lexpos = self.details.lexpos
        #elif isinstance(self.details, ply.lex.Lexer):
        #    print "this is a Lexer"
        #    lexpos = self.details.lexpos - len(self.symbol)
        try:
            #lexpos = self.details.lexpos
            lexpos = self.lexer.lexpos
            errpos = (lexpos - 1) - errlinepos
            errlinebefore = lines[self.errlineno]\
                [:(lexpos - errlinepos)]
            errlinebefore = len(errlinebefore.expandtabs())
        except AttributeError:
            lexpos = None
        linenofmtlen = len(str(lastline))
        lineprintfmt = "%%s%%%dd %%s"%(linenofmtlen)
        for lineno in xrange(firstline, lastline):
            if lineno == self.errlineno:
                #print ""
                prefix = "-> "
            else:
                prefix = "   "
            print lineprintfmt%(prefix, lineno + 1,
                                lines[lineno].expandtabs())
            if lineno == self.errlineno:
                if lexpos:
                    prefixlen = len(prefix) + linenofmtlen + 1
                    print "%s%s"%(" "*(prefixlen + errlinebefore),
                                  "^"*len(self.symbol or ""))
                else:
                    print ""
        if self.parser.parent:
            parent = self.parser.parent
            print "Included from %s"%(parent.filename)
            parent = parent.parent
            while parent:
                print "              %s"%(parent.filename)
                parent = parent.parent
        if self.more_details:
            if "print_details" in dir(self.more_details):
                self.more_details.print_details()
            else:
                print self.more_details
        return

class StatementNotAllowed(ParseError):

    def __init(self, parser, p, statement):
        super(StatementNotAllowedInConf, self).__init__(
            parser, "%s statement not allowed"%(statement), p)
        return

class FileNotFound(ParseError):

    def __init__(self, parser, filename, p, lineno=None):
        self.filename = filename
        super(FileNotFound, self).__init__(
            parser, "%s not found"%(filename), p, lineno=lineno)
        return

__all__ = [
    "bblex", "bbparse", "confparse",
    "ParseError", "StatementNotAllowed", "FileNotFound",
    "bblexer",
    ]

import bblex
import bbparse
import confparse
<|endoftext|>


<commit_before>#  Copyright 2008-2015 Nokia Networks
#  Copyright 2016-     Robot Framework Foundation
#
#  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.

import os

from robotide import robotapi

def NewTestCaseFile(path):
    datafile = robotapi.TestCaseFile(source=path)
    _create_missing_directories(datafile.directory)
    return datafile

def NewTestDataDirectory(path):
    dirname = os.path.dirname(path)
    datafile = robotapi.TestDataDirectory(source=dirname)
    datafile.initfile = path
    _create_missing_directories(dirname)
    return datafile

def _create_missing_directories(dirname):
    if not os.path.isdir(dirname):
        os.makedirs(dirname)
<commit_msg>Added default template when creating new suite (i.e. `*** Test Cases ***`) (#1951)<commit_after>#  Copyright 2008-2015 Nokia Networks
#  Copyright 2016-     Robot Framework Foundation
#
#  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.

import os

from robotide import robotapi

def NewTestCaseFile(path):
    datafile = robotapi.TestCaseFile(source=path)
    datafile.start_table(['Test Cases'])
    _create_missing_directories(datafile.directory)
    return datafile

def NewTestDataDirectory(path):
    dirname = os.path.dirname(path)
    datafile = robotapi.TestDataDirectory(source=dirname)
    datafile.initfile = path
    _create_missing_directories(dirname)
    return datafile

def _create_missing_directories(dirname):
    if not os.path.isdir(dirname):
        os.makedirs(dirname)
<|endoftext|>


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

"""
Defines constant values for the ScrambleSuit protocol.
The values below are not supposed to be changed. If you don't obey, be at least
careful because things could break easily.
"""

# Key size for the AES session key and its IV in bytes.
SESSION_KEY_SIZE = IV_SIZE = 32

# Key size for the master key in bytes.
MASTER_KEY_SIZE = 32

# The maximum padding length to be appended to the puzzle in bytes.
MAX_PADDING_LENGTH = 4096

# Length of the time-lock puzzle (consisting of `n' and `Ck') in bytes.
PUZZLE_LENGTH = 128

# The length of the puzzle's modulus `n' in bits.
PUZZLE_MODULUS_LENGTH = 512

# Approximate CPU time in seconds necessary to solve the puzzle.
PUZZLE_UNLOCK_TIME = 120

# Length of the magic values in bytes.
MAGIC_LENGTH = 32

# States which are used for the protocol state machine.
ST_WAIT_FOR_PUZZLE = 0
ST_SOLVING_PUZZLE = 1
ST_WAIT_FOR_MAGIC = 2
ST_CONNECTED = 3

# Length of ScrambleSuit's header in bytes.
HDR_LENGTH = 16 + 2 + 2

# Length of the HMAC-SHA256-128 in bytes.
HMAC_LENGTH = 16

# Length of ScrambleSuit's MTU in bytes.
MTU = 1460

# The prefix prepended to the master key which is locked inside the time-lock
# puzzle. The client looks for this prefix to verify that the puzzle was
# unlocked successfully.
MASTER_KEY_PREFIX = "MasterKey="

# The protocol name which is used in log messages.
TRANSPORT_NAME = "ScrambleSuit"

# SHA256's digest size in bytes.
SHA256_DIGEST_SIZE = 32
<commit_msg>Add new protocol state and new constants for session tickets.<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Defines constant values for the ScrambleSuit protocol.
The values below are not supposed to be changed. If you don't obey, be at least
careful because things could break easily.
"""

# Key size for the AES session key and its IV in bytes.
SESSION_KEY_SIZE = IV_SIZE = 32

# Key size for the master key in bytes.
MASTER_KEY_SIZE = 32

# The maximum padding length to be appended to the puzzle in bytes.
MAX_PADDING_LENGTH = 4096

# Length of the time-lock puzzle (consisting of `n' and `Ck') in bytes.
PUZZLE_LENGTH = 128

# The length of the puzzle's modulus `n' in bits.
PUZZLE_MODULUS_LENGTH = 512

# Approximate CPU time in seconds necessary to solve the puzzle.
PUZZLE_UNLOCK_TIME = 120

# Length of the magic values in bytes.
MAGIC_LENGTH = 32

# States which are used for the protocol state machine.
ST_WAIT_FOR_TICKET = 0
ST_WAIT_FOR_PUZZLE = 1
ST_SOLVING_PUZZLE = 2
ST_WAIT_FOR_MAGIC = 3
ST_CONNECTED = 4

# Length of ScrambleSuit's header in bytes.
HDR_LENGTH = 16 + 2 + 2

# Length of the HMAC-SHA256-128 in bytes.
HMAC_LENGTH = 16

# Length of ScrambleSuit's MTU in bytes.
MTU = 1460

# Length of a session ticket in bytes.
SESSION_TICKET_LENGTH = 112

# Life time of session tickets in hours.
SESSION_TICKET_LIFETIME = 24 * 7

# The prefix prepended to the master key which is locked inside the time-lock
# puzzle. The client looks for this prefix to verify that the puzzle was
# unlocked successfully.
MASTER_KEY_PREFIX = "MasterKey="

# The protocol name which is used in log messages.
TRANSPORT_NAME = "ScrambleSuit"

# SHA256's digest size in bytes.
SHA256_DIGEST_SIZE = 32
<|endoftext|>


<commit_before>#  Copyright 2008-2012 Nokia Siemens Networks Oyj
#
#  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.
import os
import sqlite3
import time
from robotide.preferences.settings import SETTINGS_DIRECTORY
from robotide.spec.iteminfo import LibraryKeywordInfo

CREATION_SCRIPT = """\
CREATE TABLE libraries (id INTEGER PRIMARY KEY,
                        name TEXT,
                        arguments TEXT,
                        last_updated REAL);
CREATE TABLE keywords (name TEXT,
                       doc TEXT,
                       arguments TEXT,
                       library_name TEXT,
                       library INTEGER,
                       FOREIGN KEY(library) REFERENCES libraries(id));
"""

#FIXME! SIDE-EFFECTS DURING IMPORTING!

DB_DIR = os.path.join(SETTINGS_DIRECTORY, 'ride')

if not os.path.exists(DB_DIR):
    os.makedirs(DB_DIR)

DATABASE_FILE = os.path.join(DB_DIR, 'librarykeywords.db')

if not os.path.exists(DATABASE_FILE):
    connection = sqlite3.connect(DATABASE_FILE)
    connection.executescript(CREATION_SCRIPT)
    connection.commit()
    connection.close()
else:
    try:
        connection = sqlite3.connect(DATABASE_FILE)
        connection.execute('select id, name, arguments, last_updated from libraries')
        connection.execute('select name, doc, arguments, library_name, library from keywords')
        connection.close()
    except sqlite3.DatabaseError:
        os.remove(DATABASE_FILE)
        connection = sqlite3.connect(DATABASE_FILE)
        connection.executescript(CREATION_SCRIPT)
        connection.commit()
        connection.close()

class LibraryDatabase(object):

    def __init__(self, database):
        self._connection = sqlite3.connect(database, timeout=30.0)

    def create_database(self):
        self._connection.executescript(CREATION_SCRIPT)
        self._connection.commit()

    def close(self):
        self._connection.close()

    def insert_library_keywords(self, library_name, library_arguments, keywords):
        self._remove_old_versions(library_name, library_arguments)
        lib = self._insert_library(library_name, library_arguments)
        keyword_values = [[kw.name, kw.doc, u' | '.join(kw.arguments), kw.source, lib[0]] for kw in keywords if kw is not None]
        self._insert_library_keywords(keyword_values)
        self._connection.commit()

    def _remove_old_versions(self, name, arguments):
        old_versions = self._connection.execute('select id from libraries where name = ? and arguments = ?', (name, unicode(arguments))).fetchall()
        self._connection.executemany('delete from keywords where library = ?', old_versions)
        self._connection.execute('delete from libraries where name = ? and arguments = ?', (name, unicode(arguments)))

    def update_library_timestamp(self, name, arguments, milliseconds=None):
        self._connection.execute('update libraries set last_updated = ? where name = ? and arguments = ?', (milliseconds or time.time(), name, unicode(arguments)))

    def fetch_library_keywords(self, library_name, library_arguments):
        lib = self._fetch_lib(library_name, library_arguments)
        if lib is None:
            return []
        return [LibraryKeywordInfo(name, doc, library_name, arguments.split(u' | ') if arguments else [])
                for name, doc, arguments, library_name in
                self._connection.execute('select name, doc, arguments, library_name from keywords where library = ?', [lib[0]])]

    def library_exists(self, library_name, library_arguments):
        return self._fetch_lib(library_name, library_arguments) is not None

    def get_library_last_updated(self, library_name, library_arguments):
        lib = self._fetch_lib(library_name, library_arguments)
        if not lib:
            return 0.0
        return lib[3]

    def _insert_library(self, name, arguments):
        self._connection.execute('insert into libraries values (null, ?, ?, ?)', (name, unicode(arguments), time.time()))
        return self._fetch_lib(name, arguments)

    def _fetch_lib(self, name, arguments):
        t = self._connection.execute('select max(last_updated) from libraries where name = ? and arguments = ?', (name, unicode(arguments))).fetchone()[0]
        return self._connection.execute('select * from libraries where name = ? and arguments = ? and last_updated = ?', (name, unicode(arguments), t)).fetchone()

    def _insert_library_keywords(self, data):
        self._connection.executemany('insert into keywords values (?, ?, ?, ?, ?)', data)
<commit_msg>remove old library versions only after new ones have been inserted<commit_after>#  Copyright 2008-2012 Nokia Siemens Networks Oyj
#
#  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.
import os
import sqlite3
import time
from robotide.preferences.settings import SETTINGS_DIRECTORY
from robotide.spec.iteminfo import LibraryKeywordInfo

CREATION_SCRIPT = """\
CREATE TABLE libraries (id INTEGER PRIMARY KEY,
                        name TEXT,
                        arguments TEXT,
                        last_updated REAL);
CREATE TABLE keywords (name TEXT,
                       doc TEXT,
                       arguments TEXT,
                       library_name TEXT,
                       library INTEGER,
                       FOREIGN KEY(library) REFERENCES libraries(id));
"""

#FIXME! SIDE-EFFECTS DURING IMPORTING!

DB_DIR = os.path.join(SETTINGS_DIRECTORY, 'ride')

if not os.path.exists(DB_DIR):
    os.makedirs(DB_DIR)

DATABASE_FILE = os.path.join(DB_DIR, 'librarykeywords.db')

if not os.path.exists(DATABASE_FILE):
    connection = sqlite3.connect(DATABASE_FILE)
    connection.executescript(CREATION_SCRIPT)
    connection.commit()
    connection.close()
else:
    try:
        connection = sqlite3.connect(DATABASE_FILE)
        connection.execute('select id, name, arguments, last_updated from libraries')
        connection.execute('select name, doc, arguments, library_name, library from keywords')
        connection.close()
    except sqlite3.DatabaseError:
        os.remove(DATABASE_FILE)
        connection = sqlite3.connect(DATABASE_FILE)
        connection.executescript(CREATION_SCRIPT)
        connection.commit()
        connection.close()

class LibraryDatabase(object):

    def __init__(self, database):
        self._connection = sqlite3.connect(database, timeout=30.0)

    def create_database(self):
        self._connection.executescript(CREATION_SCRIPT)
        self._connection.commit()

    def close(self):
        self._connection.close()

    def insert_library_keywords(self, library_name, library_arguments, keywords):
        old_versions = self._connection.execute('select id from libraries where name = ? and arguments = ?', (library_name, unicode(library_arguments))).fetchall()
        lib = self._insert_library(library_name, library_arguments)
        keyword_values = [[kw.name, kw.doc, u' | '.join(kw.arguments), kw.source, lib[0]] for kw in keywords if kw is not None]
        self._insert_library_keywords(keyword_values)
        self._connection.executemany('delete from keywords where library = ?', old_versions)
        self._connection.executemany('delete from libraries where id = ?', old_versions)
        self._connection.commit()

    def update_library_timestamp(self, name, arguments, milliseconds=None):
        self._connection.execute('update libraries set last_updated = ? where name = ? and arguments = ?', (milliseconds or time.time(), name, unicode(arguments)))

    def fetch_library_keywords(self, library_name, library_arguments):
        lib = self._fetch_lib(library_name, library_arguments)
        if lib is None:
            return []
        return [LibraryKeywordInfo(name, doc, library_name, arguments.split(u' | ') if arguments else [])
                for name, doc, arguments, library_name in
                self._connection.execute('select name, doc, arguments, library_name from keywords where library = ?', [lib[0]])]

    def library_exists(self, library_name, library_arguments):
        return self._fetch_lib(library_name, library_arguments) is not None

    def get_library_last_updated(self, library_name, library_arguments):
        lib = self._fetch_lib(library_name, library_arguments)
        if not lib:
            return 0.0
        return lib[3]

    def _insert_library(self, name, arguments):
        self._connection.execute('insert into libraries values (null, ?, ?, ?)', (name, unicode(arguments), time.time()))
        return self._fetch_lib(name, arguments)

    def _fetch_lib(self, name, arguments):
        t = self._connection.execute('select max(last_updated) from libraries where name = ? and arguments = ?', (name, unicode(arguments))).fetchone()[0]
        return self._connection.execute('select * from libraries where name = ? and arguments = ? and last_updated = ?', (name, unicode(arguments), t)).fetchone()

    def _insert_library_keywords(self, data):
        self._connection.executemany('insert into keywords values (?, ?, ?, ?, ?)', data)
<|endoftext|>


<commit_before>import re
from copy import copy
from enum import Enum, auto
from typing import Optional

from gilgamesh.errors import GilgameshError

M_BIT = 5
X_BIT = 4

class State:
    def __init__(self, p=0b0011_0000, m: Optional[int] = None, x: Optional[int] = None):
        # State can be specified by either passing a P integer value,
        # or individual M & X values to specify A and X/Y sizes.
        if (m is None) and (x is None):
            self.p = p
        else:
            assert (m is not None) and (x is not None)
            self.p = m << M_BIT
            self.p |= x << X_BIT

    @classmethod
    def from_expr(cls, expr: str) -> "State":
        # TODO: Write tests for this.
        if not (
            re.match(r"m=(0|1),x=(0|1)", expr) or re.match(r"x=(0|1),m=(0|1)", expr)
        ):
            raise GilgameshError("Unknown syntax.")

        expressions = expr.split(",")
        return cls(
            **{
                str(register): int(value)
                for register, value in (e.split("=") for e in expressions)
            }
        )

    def __str__(self) -> str:
        return f"m={self.m},x={self.x}"

    def __repr__(self) -> str:
        return f"<State: {self}>"

    def __eq__(self, other) -> bool:
        return self.p == other.p

    def __hash__(self) -> int:
        return hash(self.p)

    @property
    def m(self) -> int:
        return (self.p >> M_BIT) & 1

    @m.setter
    def m(self, m: int) -> None:
        if m:
            self.set(1 << M_BIT)
        else:
            self.reset(1 << M_BIT)

    @property
    def x(self) -> int:
        return (self.p >> X_BIT) & 1

    @x.setter
    def x(self, x: int) -> None:
        if x:
            self.set(1 << X_BIT)
        else:
            self.reset(1 << X_BIT)

    @property
    def a_size(self) -> int:
        return 1 if self.m else 2

    @property
    def x_size(self) -> int:
        return 1 if self.x else 2

    def set(self, p: int) -> None:
        p &= (1 << M_BIT) | (1 << X_BIT)
        self.p |= p

    def reset(self, p: int) -> None:
        p &= (1 << M_BIT) | (1 << X_BIT)
        p = ~p & 0xFF
        self.p &= p

class UnknownReason(Enum):
    KNOWN = auto()
    UNKNOWN = auto()
    RECURSION = auto()
    INDIRECT_JUMP = auto()
    STACK_MANIPULATION = auto()
    SUSPECT_INSTRUCTION = auto()
    MULTIPLE_RETURN_STATES = auto()

class StateChange:
    """Change in processor state caused by the execution of a subroutine."""

    def __init__(
        self,
        m: Optional[int] = None,
        x: Optional[int] = None,
        unknown_reason: Optional[UnknownReason] = None,
    ):
        self.m = m
        self.x = x
        self.unknown_reason = unknown_reason or UnknownReason.KNOWN
        self.asserted = False

    @property
    def unknown(self):
        return self.unknown_reason != UnknownReason.KNOWN

    @classmethod
    def from_expr(cls, expr: str) -> "StateChange":
        # TODO: Validate expression.
        if expr == "none":
            return cls()
        elif expr == "unknown":
            raise NotImplementedError

        expressions = expr.split(",")
        if 1 <= len(expressions) <= 2:
            return cls(
                **{  # type: ignore
                    str(register): int(value)
                    for register, value in (e.split("=") for e in expressions)
                }
            )
        else:
            raise GilgameshError("Unknown syntax.")

    def __str__(self) -> str:
        if self.unknown:
            return "unknown"

        r = ""
        m_str = [f"m={self.m}"] if self.m is not None else []
        x_str = [f"x={self.x}"] if self.x is not None else []
        if m_str or x_str:
            r += ",".join([*m_str, *x_str])
        else:
            r += "none"
        return r

    def __repr__(self) -> str:
        return f"<StateChange: {self}>"

    def __eq__(self, other) -> bool:
        return (self.unknown_reason == other.unknown_reason) or (
            (self.m == other.m) and (self.x == other.x)
        )

    def __hash__(self) -> int:
        if self.unknown:
            return hash((None, None, self.unknown_reason))
        return hash((self.m, self.x, self.unknown_reason))

    @property
    def unknown_reason_str(self) -> str:
        return self.unknown_reason.name.lower().replace("_", " ")

    def set(self, p_change: int) -> None:
        change = State(p_change)
        self.m = 1 if change.m else self.m
        self.x = 1 if change.x else self.x

    def reset(self, p_change: int) -> None:
        change = State(p_change)
        self.m = 0 if change.m else self.m
        self.x = 0 if change.x else self.x

    def apply_inference(self, inference: "StateChange") -> None:
        # If we already knew that M was set, and we're currently
        # setting M, then we are not really changing its value.
        if (
            (inference.m is not None)
            and (self.m is not None)
            and (inference.m == self.m)
        ):
            self.m = None

        if (
            (inference.x is not None)
            and (self.x is not None)
            and (inference.x == self.x)
        ):
            self.x = None

    def simplify(self, state: State) -> "StateChange":
        change = copy(self)
        if (change.m is not None) and (state.m == change.m):
            change.m = None
        if (change.x is not None) and (state.x == change.x):
            change.x = None
        return change
<commit_msg>Fix bug when parsing unknowns<commit_after>import re
from copy import copy
from enum import Enum, auto
from typing import Optional

from gilgamesh.errors import GilgameshError

M_BIT = 5
X_BIT = 4

class State:
    def __init__(self, p=0b0011_0000, m: Optional[int] = None, x: Optional[int] = None):
        # State can be specified by either passing a P integer value,
        # or individual M & X values to specify A and X/Y sizes.
        if (m is None) and (x is None):
            self.p = p
        else:
            assert (m is not None) and (x is not None)
            self.p = m << M_BIT
            self.p |= x << X_BIT

    @classmethod
    def from_expr(cls, expr: str) -> "State":
        # TODO: Write tests for this.
        if not (
            re.match(r"m=(0|1),x=(0|1)", expr) or re.match(r"x=(0|1),m=(0|1)", expr)
        ):
            raise GilgameshError("Unknown syntax.")

        expressions = expr.split(",")
        return cls(
            **{
                str(register): int(value)
                for register, value in (e.split("=") for e in expressions)
            }
        )

    def __str__(self) -> str:
        return f"m={self.m},x={self.x}"

    def __repr__(self) -> str:
        return f"<State: {self}>"

    def __eq__(self, other) -> bool:
        return self.p == other.p

    def __hash__(self) -> int:
        return hash(self.p)

    @property
    def m(self) -> int:
        return (self.p >> M_BIT) & 1

    @m.setter
    def m(self, m: int) -> None:
        if m:
            self.set(1 << M_BIT)
        else:
            self.reset(1 << M_BIT)

    @property
    def x(self) -> int:
        return (self.p >> X_BIT) & 1

    @x.setter
    def x(self, x: int) -> None:
        if x:
            self.set(1 << X_BIT)
        else:
            self.reset(1 << X_BIT)

    @property
    def a_size(self) -> int:
        return 1 if self.m else 2

    @property
    def x_size(self) -> int:
        return 1 if self.x else 2

    def set(self, p: int) -> None:
        p &= (1 << M_BIT) | (1 << X_BIT)
        self.p |= p

    def reset(self, p: int) -> None:
        p &= (1 << M_BIT) | (1 << X_BIT)
        p = ~p & 0xFF
        self.p &= p

class UnknownReason(Enum):
    KNOWN = auto()
    UNKNOWN = auto()
    RECURSION = auto()
    INDIRECT_JUMP = auto()
    STACK_MANIPULATION = auto()
    SUSPECT_INSTRUCTION = auto()
    MULTIPLE_RETURN_STATES = auto()

class StateChange:
    """Change in processor state caused by the execution of a subroutine."""

    def __init__(
        self,
        m: Optional[int] = None,
        x: Optional[int] = None,
        unknown_reason: Optional[UnknownReason] = None,
    ):
        self.m = m
        self.x = x
        self.unknown_reason = unknown_reason or UnknownReason.KNOWN
        self.asserted = False

    @property
    def unknown(self):
        return self.unknown_reason != UnknownReason.KNOWN

    @classmethod
    def from_expr(cls, expr: str) -> "StateChange":
        # TODO: Validate expression.
        if expr == "none":
            return cls()
        elif expr == "unknown":
            return cls(unknown_reason=UnknownReason.UNKNOWN)

        expressions = expr.split(",")
        if 1 <= len(expressions) <= 2:
            return cls(
                **{  # type: ignore
                    str(register): int(value)
                    for register, value in (e.split("=") for e in expressions)
                }
            )
        else:
            raise GilgameshError("Unknown syntax.")

    def __str__(self) -> str:
        if self.unknown:
            return "unknown"

        r = ""
        m_str = [f"m={self.m}"] if self.m is not None else []
        x_str = [f"x={self.x}"] if self.x is not None else []
        if m_str or x_str:
            r += ",".join([*m_str, *x_str])
        else:
            r += "none"
        return r

    def __repr__(self) -> str:
        return f"<StateChange: {self}>"

    def __eq__(self, other) -> bool:
        return (self.unknown_reason == other.unknown_reason) or (
            (self.m == other.m) and (self.x == other.x)
        )

    def __hash__(self) -> int:
        if self.unknown:
            return hash((None, None, self.unknown_reason))
        return hash((self.m, self.x, self.unknown_reason))

    @property
    def unknown_reason_str(self) -> str:
        return self.unknown_reason.name.lower().replace("_", " ")

    def set(self, p_change: int) -> None:
        change = State(p_change)
        self.m = 1 if change.m else self.m
        self.x = 1 if change.x else self.x

    def reset(self, p_change: int) -> None:
        change = State(p_change)
        self.m = 0 if change.m else self.m
        self.x = 0 if change.x else self.x

    def apply_inference(self, inference: "StateChange") -> None:
        # If we already knew that M was set, and we're currently
        # setting M, then we are not really changing its value.
        if (
            (inference.m is not None)
            and (self.m is not None)
            and (inference.m == self.m)
        ):
            self.m = None

        if (
            (inference.x is not None)
            and (self.x is not None)
            and (inference.x == self.x)
        ):
            self.x = None

    def simplify(self, state: State) -> "StateChange":
        change = copy(self)
        if (change.m is not None) and (state.m == change.m):
            change.m = None
        if (change.x is not None) and (state.x == change.x):
            change.x = None
        return change
<|endoftext|>


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

###############################################################################
#  Copyright 2013 Kitware Inc.
#
#  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.
###############################################################################

import cherrypy.process.plugins
import datetime
import errno
import girder
import json
import six
import os

from girder.api import access
from girder.constants import SettingKey, VERSION
from girder.models.model_base import GirderException
from girder.utility import plugin_utilities
from girder.utility import system
from girder.utility.progress import ProgressContext
from ..describe import API_VERSION, Description
from ..rest import Resource, RestException

ModuleStartTime = datetime.datetime.utcnow()

class System(Resource):
    """
    The system endpoints are for querying and managing system-wide properties.
    """
    def __init__(self):
        self.resourceName = 'system'
        self.route('DELETE', ('setting',), self.unsetSetting)
        self.route('GET', ('version',), self.getVersion)
        self.route('GET', ('setting',), self.getSetting)
        self.route('GET', ('plugins',), self.getPlugins)
        self.route('PUT', ('setting',), self.setSetting)
        self.route('PUT', ('plugins',), self.enablePlugins)
        self.route('PUT', ('restart',), self.restartServer)
        self.route('GET', ('uploads',), self.getPartialUploads)
        self.route('DELETE', ('uploads',), self.discardPartialUploads)
        self.route('GET', ('check',), self.systemStatus)
        self.route('PUT', ('check',), self.systemConsistencyCheck)
        self.route('GET', ('log',), self.getLog)

    @access.admin
    def setSetting(self, params):
        """
        Set a system-wide setting. Validation of the setting is performed in
        the setting model. If the setting is a valid JSON string, it will be
        passed to the model as the corresponding dict, otherwise it is simply
        passed as a raw string.
        """
        if 'list' in params:
            try:
                settings = json.loads(params['list'])

                if type(settings) is not list:
                    raise ValueError()
            except ValueError:
                raise RestException('List was not a valid JSON list.')
        else:
            self.requireParams(('key', 'value'), params)
            settings = ({'key': params['key'], 'value': params['value']},)

        for setting in settings:
            if setting['value'] is None:
                value = None
            else:
                try:
                    if isinstance(setting['value'], six.string_types):
                        value = json.loads(setting['value'])
                    else:
                        value = setting['value']
                except ValueError:
                    value = setting['value']

            if value is None:
                self.model('setting').unset(key=setting['key'])
            else:
                self.model('setting').set(key=setting['key'], value=value)

        return True
    setSetting.description = (
        Description('Set the value for a system setting, or a list of them.')
        .notes("""Must be a system administrator to call this. If the value
               passed is a valid JSON object, it will be parsed and stored
               as an object.""")
        .param('key', 'The key identifying this setting.', required=False)
        .param('value', 'The value for this setting.', required=False)
        .param('list', 'A JSON list of objects with key and value representing '
               'a list of settings to set.', required=False)
        .errorResponse('You are not a system administrator.', 403))

    @access.admin
    def getSetting(self, params):
        getFuncName = 'get'
        funcParams = {}
        if 'default' in params:
            if params['default'] == 'none':
                funcParams['default'] = None
            elif params['default'] == 'default':
                getFuncName = 'getDefault'
            elif len(params['default']):
                raise RestException("Default was not 'none', 'default', or "
                                    "blank.")
        getFunc = getattr(self.model('setting'), getFuncName)
        if 'list' in params:
            try:
                keys = json.loads(params['list'])

                if type(keys) is not list:
                    raise ValueError()
            except ValueError:
                raise RestException('List was not a valid JSON list.')

            return {k: getFunc(k, **funcParams) for k in keys}
        else:
            self.requireParams('key', params)
            return getFunc(params['key'], **funcParams)
    getSetting.description = (
        Description('Get the value of a system setting, or a list of them.')
        .notes('Must be a system administrator to call this.')
        .param('key', 'The key identifying this setting.', required=False)
        .param('list', 'A JSON list of keys representing a set of settings to'
               ' return.', required=False)
        .param('default', 'If "none", return a null value if a setting is '
               'currently the default value.  If "default", return the '
               'default value of the setting(s).', required=False)
        .errorResponse('You are not a system administrator.', 403))

    @access.admin
    def getPlugins(self, params):
        """
        Return the plugin information for the system. This includes a list of
        all of the currently enabled plugins, as well as
        """
        return {
            'all': plugin_utilities.findAllPlugins(),
            'enabled': self.model('setting').get(SettingKey.PLUGINS_ENABLED)
        }
    getPlugins.description = (
        Description('Get the lists of all available and all enabled plugins.')
        .notes('Must be a system administrator to call this.')
        .errorResponse('You are not a system administrator.', 403))

    @access.public
    def getVersion(self, params):
        version = dict(**VERSION)
        version['apiVersion'] = API_VERSION
        version['serverStartDate'] = ModuleStartTime
        return version
    getVersion.description = Description(
        'Get the version information for this server.')

    @access.admin
    def enablePlugins(self, params):
        self.requireParams('plugins', params)
        try:
            plugins = json.loads(params['plugins'])
        except ValueError:
            raise RestException('Plugins parameter should be a JSON list.')

        return self.model('setting').set(SettingKey.PLUGINS_ENABLED, plugins)
    enablePlugins.description = (
        Description('Set the list of enabled plugins for the system.')
        .responseClass('Setting')
        .notes('Must be a system administrator to call this.')
        .param('plugins', 'JSON array of plugins to enable.')
        .errorResponse('You are not a system administrator.', 403))

    @access.admin
    def unsetSetting(self, params):
        self.requireParams('key', params)
        return self.model('setting').unset(params['key'])
    unsetSetting.description = (
        Description('Unset the value for a system setting.')
        .notes("""Must be a system administrator to call this. This is used to
               explicitly restore a setting to its default value.""")
        .param('key', 'The key identifying the setting to unset.')
        .errorResponse('You are not a system administrator.', 403))

    @access.admin
    def getPartialUploads(self, params):
        limit, offset, sort = self.getPagingParameters(params, 'updated')
        uploadList = list(self.model('upload').list(
            filters=params, limit=limit, offset=offset, sort=sort))
        untracked = self.boolParam('includeUntracked', params, default=True)
        if untracked and (limit == 0 or len(uploadList) < limit):
            assetstoreId = params.get('assetstoreId', None)
            untrackedList = self.model('upload').untrackedUploads('list',
                                                                  assetstoreId)
            if limit == 0:
                uploadList += untrackedList
            elif len(uploadList) < limit:
                uploadList += untrackedList[:limit-len(uploadList)]
        return uploadList
    getPartialUploads.description = (
        Description('Get a list of uploads that have not been finished.')
        .notes("Must be a system administrator to call this.")
        .param('uploadId', 'List only a specific upload.', required=False)
        .param('userId', 'Restrict listing uploads to those started by a '
               'specific user.', required=False)
        .param('parentId', 'Restrict listing uploads to those within a '
               'specific folder or item.', required=False)
        .param('assetstoreId', 'Restrict listing uploads within a specific '
               'assetstore.', required=False)
        .param('minimumAge', 'Restrict listing uploads to those that are at '
               'least this many days old.', required=False)
        .param('includeUntracked', 'Some assetstores can have partial uploads '
               'that are no longer in the Girder database.  If this is True, '
               'include all of them (only filtered by assetstoreId) in the '
               'result list.  Default True.',
               required=False, dataType='boolean')
        .param('limit', "Result set size limit (default=50).", required=False,
               dataType='int')
        .param('offset', "Offset into result set (default=0).", required=False,
               dataType='int')
        .param('sort', "Field to sort the upload list by (default=age)",
               required=False)
        .param('sortdir', "1 for ascending, -1 for descending (default=1)",
               required=False, dataType='int')
        .errorResponse('You are not a system administrator.', 403))

    @access.admin
    def discardPartialUploads(self, params):
        uploadList = list(self.model('upload').list(filters=params))
        # Move the results to list that isn't a cursor so we don't have to have
        # the cursor sitting around while we work on the data.
        for upload in uploadList:
            try:
                self.model('upload').cancelUpload(upload)
            except OSError as exc:
                if exc.errno == errno.EACCES:
                    raise GirderException(
                        'Failed to delete upload.',
                        'girder.api.v1.system.delete-upload-failed')
                raise
        untracked = self.boolParam('includeUntracked', params, default=True)
        if untracked:
            assetstoreId = params.get('assetstoreId', None)
            uploadList += self.model('upload').untrackedUploads('delete',
                                                                assetstoreId)
        return uploadList
    discardPartialUploads.description = (
        Description('Discard uploads that have not been finished.')
        .notes("""Must be a system administrator to call this. This frees
               resources that were allocated for the uploads and clears the
               uploads from database.""")
        .param('uploadId', 'Clear only a specific upload.', required=False)
        .param('userId', 'Restrict clearing uploads to those started by a '
               'specific user.', required=False)
        .param('parentId', 'Restrict clearing uploads to those within a '
               'specific folder or item.', required=False)
        .param('assetstoreId', 'Restrict clearing uploads within a specific '
               'assetstore.', required=False)
        .param('minimumAge', 'Restrict clearing uploads to those that are at '
               'least this many days old.', required=False)
        .param('includeUntracked', 'Some assetstores can have partial uploads '
               'that are no longer in the Girder database.  If this is True, '
               'remove all of them (only filtered by assetstoreId).  Default '
               'True.',
               required=False, dataType='boolean')
        .errorResponse('You are not a system administrator.', 403)
        .errorResponse('Failed to delete upload', 500))

    @access.admin
    def restartServer(self, params):
        """
        Restart the girder rest server.  This reloads everything, which is
        currently necessary to enable or disable a plugin.
        """
        class Restart(cherrypy.process.plugins.Monitor):
            def __init__(self, bus, frequency=1):
                cherrypy.process.plugins.Monitor.__init__(
                    self, bus, self.run, frequency)

            def start(self):
                cherrypy.process.plugins.Monitor.start(self)

            def run(self):
                self.bus.log('Restarting.')
                self.thread.cancel()
                self.bus.restart()

        restart = Restart(cherrypy.engine)
        restart.subscribe()
        restart.start()
        return {
            'restarted': datetime.datetime.utcnow()
        }
    restartServer.description = (
        Description('Restart the Girder REST server.')
        .notes('Must be a system administrator to call this.')
        .errorResponse('You are not a system administrator.', 403))

    @access.public
    def systemStatus(self, params):
        mode = params.get('mode', 'basic')
        user = self.getCurrentUser()
        if mode != 'basic':
            self.requireAdmin(user)
        status = system.getStatus(mode, user)
        status["requestBase"] = cherrypy.request.base.rstrip('/')
        return status
    systemStatus.description = (
        Description('Report the current system status.')
        .notes('Must be a system administrator to call this with any mode '
               'other than basic.')
        .param('mode', 'Select details to return.  "quick" are the details '
               'that can be answered without much load on the system.  "slow" '
               'also includes some resource-intensive queries.',
               required=False, enum=['basic', 'quick', 'slow'])
        .errorResponse('You are not a system administrator.', 403))

    @access.admin
    def systemConsistencyCheck(self, params):
        results = {}
        progress = self.boolParam('progress', params, default=False)
        models = ('item', )
        steps = 0
        if progress:
            for model in models:
                count, changed = self.model(model).checkConsistency(
                    stage='count')
                steps += count
        with ProgressContext(progress, user=self.getCurrentUser(),
                             title='Checking system', total=steps,
                             message='Checking system...') as ctx:
            for model in models:
                count, removed = self.model(model).checkConsistency(
                    stage='remove', progress=ctx)
                if removed:
                    results[model+'Removed'] = removed
            revmodels = list(models)
            revmodels.reverse()
            for model in revmodels:
                count, corrected = self.model(model).checkConsistency(
                    stage='verify', progress=ctx)
                if count:
                    results[model+'Count'] = count
                if corrected:
                    results[model+'Corrected'] = corrected
            # TODO:
            # * check that all files are associated with an existing item
            # * check that all files exist within their assetstore and are the
            #   expected size
            # * check that all folders have a valid ancestor tree leading to a
            #   user or collection
            # * check that all folders have the correct baseParentId and
            #   baseParentType
            # * check that all groups contain valid users
            # * check that all resources validate
            # * for filesystem assetstores, find files that are not tracked.
            # * for gridfs assetstores, find chunks that are not tracked.
            # * for s3 assetstores, find elements that are not tracked.
        return results
    systemConsistencyCheck.description = (
        Description('Perform a variety of system checks to verify that all is '
                    'well.')
        .notes("""Must be a system administrator to call this.  This verifies
               and corrects some issues, such as incorrect folder sizes.""")
        .param('progress', 'Whether to record progress on this task. Default '
               'is false.', required=False, dataType='boolean')
        .errorResponse('You are not a system administrator.', 403))

    @access.admin
    def getLog(self, params):
        self.requireParams(['log', 'bytes'], params)
        if params['log'] not in ('error', 'info'):
            raise RestException('Log should be "error" or "info".')

        path = girder.getLogPaths()[params['log']]
        filesize = os.path.getsize(path)
        length = int(params['bytes']) or filesize

        def stream():
            yield '=== Last %d bytes of %s: ===\n\n' % (
                min(length, filesize), path
            )

            with open(path, 'rb') as f:
                if length < filesize:
                    f.seek(-length, os.SEEK_END)
                while True:
                    data = f.read(65536)
                    if not data:
                        break
                    yield data
        return stream
    getLog.description = (
        Description('Show the most recent contents of the server logs.')
        .notes('Must be a system administrator to call this.')
        .param('bytes', 'Controls how many bytes (from the end of the log) '
               'to show. Pass 0 to show the whole log.', dataType='integer',
               default=4096)
        .param('log', 'Which log to tail.', enum=['error', 'info'],
               default='error')
        .errorResponse('You are not a system administrator.', 403))
<commit_msg>Use variable for buffer length<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

###############################################################################
#  Copyright 2013 Kitware Inc.
#
#  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.
###############################################################################

import cherrypy.process.plugins
import datetime
import errno
import girder
import json
import six
import os

from girder.api import access
from girder.constants import SettingKey, VERSION
from girder.models.model_base import GirderException
from girder.utility import plugin_utilities
from girder.utility import system
from girder.utility.progress import ProgressContext
from ..describe import API_VERSION, Description
from ..rest import Resource, RestException

ModuleStartTime = datetime.datetime.utcnow()
LOG_BUF_SIZE = 65536

class System(Resource):
    """
    The system endpoints are for querying and managing system-wide properties.
    """
    def __init__(self):
        self.resourceName = 'system'
        self.route('DELETE', ('setting',), self.unsetSetting)
        self.route('GET', ('version',), self.getVersion)
        self.route('GET', ('setting',), self.getSetting)
        self.route('GET', ('plugins',), self.getPlugins)
        self.route('PUT', ('setting',), self.setSetting)
        self.route('PUT', ('plugins',), self.enablePlugins)
        self.route('PUT', ('restart',), self.restartServer)
        self.route('GET', ('uploads',), self.getPartialUploads)
        self.route('DELETE', ('uploads',), self.discardPartialUploads)
        self.route('GET', ('check',), self.systemStatus)
        self.route('PUT', ('check',), self.systemConsistencyCheck)
        self.route('GET', ('log',), self.getLog)

    @access.admin
    def setSetting(self, params):
        """
        Set a system-wide setting. Validation of the setting is performed in
        the setting model. If the setting is a valid JSON string, it will be
        passed to the model as the corresponding dict, otherwise it is simply
        passed as a raw string.
        """
        if 'list' in params:
            try:
                settings = json.loads(params['list'])

                if type(settings) is not list:
                    raise ValueError()
            except ValueError:
                raise RestException('List was not a valid JSON list.')
        else:
            self.requireParams(('key', 'value'), params)
            settings = ({'key': params['key'], 'value': params['value']},)

        for setting in settings:
            if setting['value'] is None:
                value = None
            else:
                try:
                    if isinstance(setting['value'], six.string_types):
                        value = json.loads(setting['value'])
                    else:
                        value = setting['value']
                except ValueError:
                    value = setting['value']

            if value is None:
                self.model('setting').unset(key=setting['key'])
            else:
                self.model('setting').set(key=setting['key'], value=value)

        return True
    setSetting.description = (
        Description('Set the value for a system setting, or a list of them.')
        .notes("""Must be a system administrator to call this. If the value
               passed is a valid JSON object, it will be parsed and stored
               as an object.""")
        .param('key', 'The key identifying this setting.', required=False)
        .param('value', 'The value for this setting.', required=False)
        .param('list', 'A JSON list of objects with key and value representing '
               'a list of settings to set.', required=False)
        .errorResponse('You are not a system administrator.', 403))

    @access.admin
    def getSetting(self, params):
        getFuncName = 'get'
        funcParams = {}
        if 'default' in params:
            if params['default'] == 'none':
                funcParams['default'] = None
            elif params['default'] == 'default':
                getFuncName = 'getDefault'
            elif len(params['default']):
                raise RestException("Default was not 'none', 'default', or "
                                    "blank.")
        getFunc = getattr(self.model('setting'), getFuncName)
        if 'list' in params:
            try:
                keys = json.loads(params['list'])

                if type(keys) is not list:
                    raise ValueError()
            except ValueError:
                raise RestException('List was not a valid JSON list.')

            return {k: getFunc(k, **funcParams) for k in keys}
        else:
            self.requireParams('key', params)
            return getFunc(params['key'], **funcParams)
    getSetting.description = (
        Description('Get the value of a system setting, or a list of them.')
        .notes('Must be a system administrator to call this.')
        .param('key', 'The key identifying this setting.', required=False)
        .param('list', 'A JSON list of keys representing a set of settings to'
               ' return.', required=False)
        .param('default', 'If "none", return a null value if a setting is '
               'currently the default value.  If "default", return the '
               'default value of the setting(s).', required=False)
        .errorResponse('You are not a system administrator.', 403))

    @access.admin
    def getPlugins(self, params):
        """
        Return the plugin information for the system. This includes a list of
        all of the currently enabled plugins, as well as
        """
        return {
            'all': plugin_utilities.findAllPlugins(),
            'enabled': self.model('setting').get(SettingKey.PLUGINS_ENABLED)
        }
    getPlugins.description = (
        Description('Get the lists of all available and all enabled plugins.')
        .notes('Must be a system administrator to call this.')
        .errorResponse('You are not a system administrator.', 403))

    @access.public
    def getVersion(self, params):
        version = dict(**VERSION)
        version['apiVersion'] = API_VERSION
        version['serverStartDate'] = ModuleStartTime
        return version
    getVersion.description = Description(
        'Get the version information for this server.')

    @access.admin
    def enablePlugins(self, params):
        self.requireParams('plugins', params)
        try:
            plugins = json.loads(params['plugins'])
        except ValueError:
            raise RestException('Plugins parameter should be a JSON list.')

        return self.model('setting').set(SettingKey.PLUGINS_ENABLED, plugins)
    enablePlugins.description = (
        Description('Set the list of enabled plugins for the system.')
        .responseClass('Setting')
        .notes('Must be a system administrator to call this.')
        .param('plugins', 'JSON array of plugins to enable.')
        .errorResponse('You are not a system administrator.', 403))

    @access.admin
    def unsetSetting(self, params):
        self.requireParams('key', params)
        return self.model('setting').unset(params['key'])
    unsetSetting.description = (
        Description('Unset the value for a system setting.')
        .notes("""Must be a system administrator to call this. This is used to
               explicitly restore a setting to its default value.""")
        .param('key', 'The key identifying the setting to unset.')
        .errorResponse('You are not a system administrator.', 403))

    @access.admin
    def getPartialUploads(self, params):
        limit, offset, sort = self.getPagingParameters(params, 'updated')
        uploadList = list(self.model('upload').list(
            filters=params, limit=limit, offset=offset, sort=sort))
        untracked = self.boolParam('includeUntracked', params, default=True)
        if untracked and (limit == 0 or len(uploadList) < limit):
            assetstoreId = params.get('assetstoreId', None)
            untrackedList = self.model('upload').untrackedUploads('list',
                                                                  assetstoreId)
            if limit == 0:
                uploadList += untrackedList
            elif len(uploadList) < limit:
                uploadList += untrackedList[:limit-len(uploadList)]
        return uploadList
    getPartialUploads.description = (
        Description('Get a list of uploads that have not been finished.')
        .notes("Must be a system administrator to call this.")
        .param('uploadId', 'List only a specific upload.', required=False)
        .param('userId', 'Restrict listing uploads to those started by a '
               'specific user.', required=False)
        .param('parentId', 'Restrict listing uploads to those within a '
               'specific folder or item.', required=False)
        .param('assetstoreId', 'Restrict listing uploads within a specific '
               'assetstore.', required=False)
        .param('minimumAge', 'Restrict listing uploads to those that are at '
               'least this many days old.', required=False)
        .param('includeUntracked', 'Some assetstores can have partial uploads '
               'that are no longer in the Girder database.  If this is True, '
               'include all of them (only filtered by assetstoreId) in the '
               'result list.  Default True.',
               required=False, dataType='boolean')
        .param('limit', "Result set size limit (default=50).", required=False,
               dataType='int')
        .param('offset', "Offset into result set (default=0).", required=False,
               dataType='int')
        .param('sort', "Field to sort the upload list by (default=age)",
               required=False)
        .param('sortdir', "1 for ascending, -1 for descending (default=1)",
               required=False, dataType='int')
        .errorResponse('You are not a system administrator.', 403))

    @access.admin
    def discardPartialUploads(self, params):
        uploadList = list(self.model('upload').list(filters=params))
        # Move the results to list that isn't a cursor so we don't have to have
        # the cursor sitting around while we work on the data.
        for upload in uploadList:
            try:
                self.model('upload').cancelUpload(upload)
            except OSError as exc:
                if exc.errno == errno.EACCES:
                    raise GirderException(
                        'Failed to delete upload.',
                        'girder.api.v1.system.delete-upload-failed')
                raise
        untracked = self.boolParam('includeUntracked', params, default=True)
        if untracked:
            assetstoreId = params.get('assetstoreId', None)
            uploadList += self.model('upload').untrackedUploads('delete',
                                                                assetstoreId)
        return uploadList
    discardPartialUploads.description = (
        Description('Discard uploads that have not been finished.')
        .notes("""Must be a system administrator to call this. This frees
               resources that were allocated for the uploads and clears the
               uploads from database.""")
        .param('uploadId', 'Clear only a specific upload.', required=False)
        .param('userId', 'Restrict clearing uploads to those started by a '
               'specific user.', required=False)
        .param('parentId', 'Restrict clearing uploads to those within a '
               'specific folder or item.', required=False)
        .param('assetstoreId', 'Restrict clearing uploads within a specific '
               'assetstore.', required=False)
        .param('minimumAge', 'Restrict clearing uploads to those that are at '
               'least this many days old.', required=False)
        .param('includeUntracked', 'Some assetstores can have partial uploads '
               'that are no longer in the Girder database.  If this is True, '
               'remove all of them (only filtered by assetstoreId).  Default '
               'True.',
               required=False, dataType='boolean')
        .errorResponse('You are not a system administrator.', 403)
        .errorResponse('Failed to delete upload', 500))

    @access.admin
    def restartServer(self, params):
        """
        Restart the girder rest server.  This reloads everything, which is
        currently necessary to enable or disable a plugin.
        """
        class Restart(cherrypy.process.plugins.Monitor):
            def __init__(self, bus, frequency=1):
                cherrypy.process.plugins.Monitor.__init__(
                    self, bus, self.run, frequency)

            def start(self):
                cherrypy.process.plugins.Monitor.start(self)

            def run(self):
                self.bus.log('Restarting.')
                self.thread.cancel()
                self.bus.restart()

        restart = Restart(cherrypy.engine)
        restart.subscribe()
        restart.start()
        return {
            'restarted': datetime.datetime.utcnow()
        }
    restartServer.description = (
        Description('Restart the Girder REST server.')
        .notes('Must be a system administrator to call this.')
        .errorResponse('You are not a system administrator.', 403))

    @access.public
    def systemStatus(self, params):
        mode = params.get('mode', 'basic')
        user = self.getCurrentUser()
        if mode != 'basic':
            self.requireAdmin(user)
        status = system.getStatus(mode, user)
        status["requestBase"] = cherrypy.request.base.rstrip('/')
        return status
    systemStatus.description = (
        Description('Report the current system status.')
        .notes('Must be a system administrator to call this with any mode '
               'other than basic.')
        .param('mode', 'Select details to return.  "quick" are the details '
               'that can be answered without much load on the system.  "slow" '
               'also includes some resource-intensive queries.',
               required=False, enum=['basic', 'quick', 'slow'])
        .errorResponse('You are not a system administrator.', 403))

    @access.admin
    def systemConsistencyCheck(self, params):
        results = {}
        progress = self.boolParam('progress', params, default=False)
        models = ('item', )
        steps = 0
        if progress:
            for model in models:
                count, changed = self.model(model).checkConsistency(
                    stage='count')
                steps += count
        with ProgressContext(progress, user=self.getCurrentUser(),
                             title='Checking system', total=steps,
                             message='Checking system...') as ctx:
            for model in models:
                count, removed = self.model(model).checkConsistency(
                    stage='remove', progress=ctx)
                if removed:
                    results[model+'Removed'] = removed
            revmodels = list(models)
            revmodels.reverse()
            for model in revmodels:
                count, corrected = self.model(model).checkConsistency(
                    stage='verify', progress=ctx)
                if count:
                    results[model+'Count'] = count
                if corrected:
                    results[model+'Corrected'] = corrected
            # TODO:
            # * check that all files are associated with an existing item
            # * check that all files exist within their assetstore and are the
            #   expected size
            # * check that all folders have a valid ancestor tree leading to a
            #   user or collection
            # * check that all folders have the correct baseParentId and
            #   baseParentType
            # * check that all groups contain valid users
            # * check that all resources validate
            # * for filesystem assetstores, find files that are not tracked.
            # * for gridfs assetstores, find chunks that are not tracked.
            # * for s3 assetstores, find elements that are not tracked.
        return results
    systemConsistencyCheck.description = (
        Description('Perform a variety of system checks to verify that all is '
                    'well.')
        .notes("""Must be a system administrator to call this.  This verifies
               and corrects some issues, such as incorrect folder sizes.""")
        .param('progress', 'Whether to record progress on this task. Default '
               'is false.', required=False, dataType='boolean')
        .errorResponse('You are not a system administrator.', 403))

    @access.admin
    def getLog(self, params):
        self.requireParams(['log', 'bytes'], params)
        if params['log'] not in ('error', 'info'):
            raise RestException('Log should be "error" or "info".')

        path = girder.getLogPaths()[params['log']]
        filesize = os.path.getsize(path)
        length = int(params['bytes']) or filesize

        def stream():
            yield '=== Last %d bytes of %s: ===\n\n' % (
                min(length, filesize), path
            )

            with open(path, 'rb') as f:
                if length < filesize:
                    f.seek(-length, os.SEEK_END)
                while True:
                    data = f.read(LOG_BUF_SIZE)
                    if not data:
                        break
                    yield data
        return stream
    getLog.description = (
        Description('Show the most recent contents of the server logs.')
        .notes('Must be a system administrator to call this.')
        .param('bytes', 'Controls how many bytes (from the end of the log) '
               'to show. Pass 0 to show the whole log.', dataType='integer',
               default=4096)
        .param('log', 'Which log to tail.', enum=['error', 'info'],
               default='error')
        .errorResponse('You are not a system administrator.', 403))
<|endoftext|>