123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- # -*- coding: utf-8 -*-
- #
- # cms.py - simple WSGI/Python based CMS script
- #
- # Copyright (C) 2011-2019 Michael Buesch <m@bues.ch>
- #
- # 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, see <http://www.gnu.org/licenses/>.
- #from cms.cython_support cimport * #@cy
- from cms.exception import *
- import html
- import datetime as datetime_mod
- import io
- import os
- import stat
- BytesIO = io.BytesIO #+cdef-public-object
- datetime = datetime_mod.datetime #+cdef-public-object
- __all__ = [
- "BytesIO",
- "datetime",
- "UPPERCASE",
- "LOWERCASE",
- "NUMBERS",
- "isiterable",
- "findNot",
- "findAny",
- "htmlEscape",
- "stringBool",
- "StrCArray",
- "str2carray",
- "carray2str",
- "fs",
- ]
- UPPERCASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' #+cdef-public-str
- LOWERCASE = 'abcdefghijklmnopqrstuvwxyz' #+cdef-public-str
- NUMBERS = '0123456789' #+cdef-public-str
- # Check if an object is iterable.
- def isiterable(obj): #@nocy
- #cdef ExBool_t isiterable(object obj) except ExBool_val: #@cy
- try:
- iter(obj)
- return True
- except TypeError:
- pass # obj is not an iterable.
- except Exception:
- raise CMSException(500, "isiterable: Unexpected exception.")
- return False
- # Find the index in 'string' that is _not_ in 'template'.
- # Start search at 'idx'.
- # Returns -1 on failure to find.
- def findNot(string, template, idx): #@nocy
- #cdef _Bool findNot(str string, str template, int64_t idx): #@cy
- #@cy cdef int64_t slen
- if idx >= 0:
- slen = len(string)
- while idx < slen:
- if string[idx] not in template:
- return idx
- idx += 1
- return -1
- # Find the index in 'string' that matches _any_ character in 'template'.
- # Start search at 'idx'.
- # Returns -1 on failure to find.
- def findAny(string, template, idx): #@nocy
- #cdef _Bool findAny(str string, str template, int64_t idx): #@cy
- #@cy cdef int64_t slen
- if idx >= 0:
- slen = len(string)
- while idx < slen:
- if string[idx] in template:
- return idx
- idx += 1
- return -1
- def htmlEscape(string): #@nocy
- #cdef str htmlEscape(str string): #@cy
- return html.escape(string, True)
- def stringBool(string, default): #@nocy
- #cdef _Bool stringBool(str string, _Bool default): #@cy
- #@cy cdef str s
- s = string.lower()
- if s in ("true", "yes", "on", "1"):
- return True
- if s in ("false", "no", "off", "0"):
- return False
- try:
- return bool(int(s))
- except ValueError:
- return default
- class StrCArray(object): #@nocy
- __slots__ = ( "_string", ) #@nocy
- def str2carray(carray, string, arrayLen): #@nocy
- if arrayLen > 0: #@nocy
- carray._string = string[:arrayLen-1] #@nocy
- def carray2str(carray, arrayLen): #@nocy
- if arrayLen > 0: #@nocy
- return carray._string #@nocy
- return "" #@nocy
- class FSHelpers(object): #+cdef
- def __init__(self):
- self.__pathSep = os.path.sep
- self.__os_stat = os.stat
- self.__os_listdir = os.listdir
- self.__stat_S_ISDIR = stat.S_ISDIR
- def __mkpath(self, path_elements): #@nocy
- #@cy cdef str __mkpath(self, tuple path_elements):
- # Do not use os.path.join, because it discards elements, if
- # one element begins with a separator (= is absolute).
- return self.__pathSep.join(path_elements)
- # Create a path string from path element strings.
- def mkpath(self, *path_elements):
- return self.__mkpath(path_elements)
- def __exists(self, path_elements): #@nocy
- #@cy cdef _Bool __exists(self, tuple path_elements):
- #@cy cdef str path
- try:
- path = self.__mkpath(path_elements)
- self.__os_stat(path.encode("UTF-8", "strict"))
- except OSError:
- return False
- except UnicodeError:
- raise CMSException(500, "Unicode decode error")
- return True
- def exists(self, *path_elements):
- return self.__exists(path_elements)
- def __exists_nonempty(self, path_elements): #@nocy
- #@cy cdef _Bool __exists_nonempty(self, tuple path_elements):
- if self.__exists(path_elements):
- return bool(self.__read(path_elements).strip())
- return False
- def exists_nonempty(self, *path_elements):
- return self.__exists_nonempty(path_elements)
- def __read(self, path_elements): #@nocy
- #@cy cdef str __read(self, tuple path_elements):
- #@cy cdef str path
- #@cy cdef bytes data
- try:
- path = self.__mkpath(path_elements)
- with open(path.encode("UTF-8", "strict"), "rb") as fd:
- data = fd.read()
- return data.decode("UTF-8", "strict")
- except IOError:
- return ""
- except UnicodeError:
- raise CMSException(500, "Unicode decode error")
- def read(self, *path_elements):
- return self.__read(path_elements)
- def __read_int(self, path_elements): #@nocy
- #@cy cdef object __read_int(self, tuple path_elements):
- #@cy cdef str data
- data = self.__read(path_elements)
- try:
- return int(data.strip())
- except ValueError:
- return None
- def read_int(self, *path_elements):
- return self.__read_int(path_elements)
- def __mtime(self, path_elements): #@nocy
- #@cy cdef object __mtime(self, tuple path_elements):
- try:
- path = self.__mkpath(path_elements).encode("UTF-8", "strict")
- return datetime.utcfromtimestamp(self.__os_stat(path).st_mtime)
- except OSError:
- raise CMSException(404)
- except UnicodeError:
- raise CMSException(500, "Unicode decode error")
- def mtime(self, *path_elements):
- return self.__mtime(path_elements)
- def __mtime_nofail(self, path_elements): #@nocy
- #@cy cdef object __mtime_nofail(self, tuple path_elements):
- try:
- return self.__mtime(path_elements)
- except CMSException:
- return datetime.utcnow()
- def mtime_nofail(self, *path_elements):
- return self.__mtime_nofail(path_elements)
- def __subdirList(self, path_elements): #@nocy
- #@cy cdef list __subdirList(self, tuple path_elements):
- #@cy cdef str path
- #@cy cdef bytes bdentry
- #@cy cdef bytes bp
- #@cy cdef str dentry
- #@cy cdef list dirListing
- #@cy cdef list ret
- try:
- ret = []
- path = self.__mkpath(path_elements)
- dirListing = self.__os_listdir(path.encode("UTF-8", "strict"))
- S_ISDIR = self.__stat_S_ISDIR
- stat = self.__os_stat
- for bdentry in dirListing:
- dentry = bdentry.decode("UTF-8", "strict")
- if dentry.startswith("."):
- continue # Omit ".", ".." and hidden entries
- if dentry.startswith("__"):
- continue # Omit system folders/files.
- try:
- bp = self.__mkpath((path, dentry)).encode("UTF-8", "strict")
- if not S_ISDIR(stat(bp).st_mode):
- continue
- except OSError:
- continue
- except UnicodeError:
- raise CMSException(500, "Unicode decode error")
- ret.append(dentry)
- return ret
- except OSError:
- return []
- except UnicodeError:
- raise CMSException(500, "Unicode decode error")
- def subdirList(self, *path_elements):
- return self.__subdirList(path_elements)
- fs = FSHelpers() #+cdef-FSHelpers
|