2021SC@SDUSC
dav_provider_tools.py是使实现自定义WsgiDAV提供商变得更容易的工具。
文件由VirtualCollection、_VirtualNonCollection、VirtualTextResource三个虚类和FileResource、DAVResolver两个普通的类构成。
虚基类VirtualCollection是一个包含静态成员列表的集合的抽象基类。将成员名传递给构造函数。Get_member()通过调用self.provider.get_resource_inst()实现
主要代码
def __init__(self, path, environ, display_info, member_name_list):#构造函数 super(VirtualCollection, self).__init__(path, environ) if compat.is_basestring(display_info): display_info = {"type": display_info} assert type(display_info) is dict assert type(member_name_list) is list self.display_info = display_info self.member_name_list = member_name_list def get_member(self, name): # raise NotImplementedError return self.provider.get_resource_inst( util.join_uri(self.path, name), self.environ )
_VirtualNonCollection是所有非集合资源的抽象基类
VirtualTextResource是一个包含一个字符串的虚拟类。
主要代码
def __init__(self, path, environ, content, display_name=None, display_type=None):#构造函数 super(VirtualTextResource, self).__init__(path, environ) self.content = content self.display_name = display_name self.display_type = display_type def get_content_length(self): return len(self.get_content().read()) def get_content_type(self): if self.name.endswith(".txt"): return "text/plain" return "text/html"
FileResource负责表示现有文件
DAVResolver主要是返回一个路径DAVResource对象(如果没有找到则为None)
主要代码
def __init__(self, parent_resolver, name):#构造函数 self.parent_resolver = parent_resolver self.name = name def resolve(self, script_name, path_info, environ): raise NotImplementedError
hg_dav_provider.py:
发布 Mercurial 存储库的 DAV 提供程序。 存储库呈现为三个顶级集合。 编辑: 包含工作目录,即所有文件。这包括未承诺的 更改和未跟踪的新文件。 该文件夹是可写的。 发布: 包含最新提交的文件,也称为“提示”。 此文件夹是只读的。 档案: 包含最近 10 个修订作为子文件夹。 此文件夹是只读的。
支持的功能:
#.将文件从 /edit/..
复制或移动到 /edit/..
文件夹将 导致“hg copy”或“hg rename”。
#.从 /edit/..
删除资源将导致 hg remove
。 #.将文件从 /edit/..
复制或移动到 /released
文件夹将 导致“hg commit”。 请注意,目标路径被忽略,而是使用源路径。 所以用户可以从 edit/..
下的某处拖动文件或文件夹 目录并将其直接放在 released
目录中以进行提交 变化。
#.要提交所有更改,只需将“/edit”文件夹拖放到 /released
文件夹。
#.创建新的集合会导致创建一个名为 .directory 的文件,然后是 hg add
ed,因为 Mercurial 不跟踪目录。
#.一些属性作为实时属性发布,例如“{hg:}date”。
这个文件也比较复杂。包含HgResource、HgResourceProvider两个类。
HgResource是所有资源的抽象基类 。类的功能比较复杂,主要的代码如下。与类DAVResource关联性强
def _check_write_access(self):#如果资源不可写,则提高 HTTP_FORBIDDEN if self.rev is not None: # 只能编辑工作目录 raise DAVError(HTTP_FORBIDDEN) def get_member(self, name):#依赖提供者获取成员实例 assert self.is_collection return self.provider.get_resource_inst( util.join_uri(self.path, name), self.environ ) def get_property_names(self, is_allprop):#Return list of supported property names in Clark Notation.See DAVResource.get_property_names() def get_property_value(self, name)#返回属性的值参见 get_property_value() def set_property_value(self, name, value, dry_run=False)#设置或删除属性值。参见 DAVResource.set_property_value() def create_empty_resource(self, name):#创建并返回一个空(长度为 0)的资源作为 self 的成员。参见 DAVResource.create_empty_resource() def create_collection(self, name)#创建一个新集合作为 self 的成员。 创建了一个虚拟成员,因为 Mercurial 不处理文件夹 def begin_write(self, content_type=None)#打开内容作为写入流。参见 DAVResource.begin_write()
类HgResourceProvider是为 VirtualResource 派生结构提供服务的 DAV 提供程序。
主要方法def _get_repo_info(self, environ, rev, reload=False)。主要负责返回包含源代码控制下的所有文件的字典。
目录信息:包含每个集合的直接成员的字典。
{文件夹路径:(收藏列表,文件列表),...}
文件:清单中所有文件路径的排序列表。
文件名:包含受源代码控制的所有文件的字典。
def get_resource_inst(self, path, environ)#返回路径的 HgResource 对象。参见 DAVProvider.get_resource_inst() def _get_log(self, limit=None)#将日志条目读入字典列表。
mysql_dav_provider.py是WebDAV 提供程序的实现,它提供了一个非常基本的、只读的 MySQL 数据库的资源层模拟。 此模块特定于 WsgiDAV 应用程序。它提供了一个 类“MySQLBrowserProvider”。
用法:(见 doc/sample_wsgidav.conf)
MySQLBrowserProvider(主机、用户、密码、数据库)
host - 数据库服务器的主机
user - 访问数据库的用户名
passwd - 访问数据库的密码
db - 数据库服务器上的数据库名称 MySQLBrowserProvider
提供了一个非常基本的只读 MySQL 数据库的资源层模拟。 它提供以下接口:
-
共享的根集合由对应于的集合组成表名
-
在每个表集合中,都有一个名为“_ENTIRE_CONTENTS”的资源.这是一个非集合资源,它返回一个 csv 表示 整桌
-
如果表只有一个主键,每条表记录也会出现使用主键作为表集合中的非集合资源 值作为其名称。此资源返回记录的 csv 表示并且还将包含记录属性作为实时属性属性名作为属性名,表名以冒号为后缀属性命名空间
包含MySQLBrowserResource、MySQLBrowserProvider两个类。
MySQLBrowserResource:表示单个现有 DAV 资源实例 。
主要函数:
def get_member_list(self)#返回(直接)集合成员名称的列表(UTF-8 字节字符串) def get_content(self)#打开内容作为阅读流。 def get_property_names(self, is_allprop)#返回一个属性的值 def get_property_value(self, name): 基本实现处理: - ``{DAV:}lockdiscovery`` 和 ``{DAV:}supportedlock`` 使用 关联的锁管理器。 - 所有其他 *live* 属性(即名称以“{DAV:}”开头)都是 委托给 self.getLivePropertyValue() - 最后,其他属性被视为*dead*,并使用 相关的物业经理,如果有的话。 def set_property_value(self, name, value, dry_run=False):#设置或删除属性值。
类MySQLBrowserProvider:负责MySQL浏览器的提供。
主要函数
def _split_path(self, path)#返回(表名,主键)请求路径的元组。 def get_resource_inst(self, path, environ)#返回路径的信息字典。调用exists() 使目录浏览非常慢。至少与PyFileServer 相比,它只是使用字符串函数来获取display_type 和displayTypeComment
virtual_dav_provider.py:提供可浏览的 DAV 提供程序的示例实现, 多分类资源树。 它演示了一些自定义 WsgiDAV 的技术。 与已发布的文件系统相比,主要有以下主要区别:
#.像“My doc 1”这样的资源有几个像“key”这样的属性,key
, orga
, tags
, status
, description
.。 也可能有一个附加文件的列表。
#.这些属性用于动态创建虚拟层次结构。 例如,如果status是draft
,则集合 <share>/by_status/draft/
被创建并且资源被映射到 <share>/by_status/draft/My doc 1
。
#.资源 My doc 1
呈现为一个集合,其中包含 一些虚拟描述文件和附加文件。
class RootCollection(DAVCollection):#解析顶级请求'/' class CategoryTypeCollection(DAVCollection):#解析'/catType' URL,例如'/by_tag'。 class CategoryCollection(DAVCollection)#解析'/catType/cat' URL,例如'/by_tag/cool'
所包含的虚类如下
class VirtualResource(DAVCollection)#虚拟“资源”,显示为工件和文件的集合 class _VirtualNonCollection(DAVNonCollection)#所有非集合资源的抽象基类。 class VirtualArtifact(_VirtualNonCollection)#一个虚拟文件,包含资源描述。 class VirtualResFile(_VirtualNonCollection)#代表一个现有的文件,它是一个 VirtualResource 的成员 class VirtualResourceProvider(DAVProvider):#为 VirtualResource 派生结构提供服务的 DAV 提供程序
VirtualResource是最为主要的类。其主要代码及相应功能如下。
def handle_delete(self):#更改 DELETE 的语义以删除资源标签 # DELETE 仅支持 '/by_tag/' 集合 if "/by_tag/" not in self.path: raise DAVError(HTTP_FORBIDDEN) # 路径必须是 '/by_tag/<tag>/<resname>' catType, tag, _rest = util.save_split(self.path.strip("/"), "/", 2) assert catType == "by_tag" assert tag in self.data["tags"] self.data["tags"].remove(tag) return True # OK def handle_copy(self, dest_path, depth_infinity): #更改 COPY 的语义以添加资源标签 # destPath 必须是 '/by_tag/<tag>/<resname>' if "/by_tag/" not in dest_path: raise DAVError(HTTP_FORBIDDEN) catType, tag, _rest = util.save_split(dest_path.strip("/"), "/", 2) assert catType == "by_tag" if tag not in self.data["tags"]: self.data["tags"].append(tag) return True # OK def handle_move(self, dest_path): #更改 MOVE 的语义以更改资源标签 # path and destPath必须是 '/by_tag/<tag>/<resname>' if "/by_tag/" not in self.path: raise DAVError(HTTP_FORBIDDEN) if "/by_tag/" not in dest_path: raise DAVError(HTTP_FORBIDDEN) catType, tag, _rest = util.save_split(self.path.strip("/"), "/", 2) assert catType == "by_tag" assert tag in self.data["tags"] self.data["tags"].remove(tag) catType, tag, _rest = util.save_split(dest_path.strip("/"), "/", 2) assert catType == "by_tag" if tag not in self.data["tags"]: self.data["tags"].append(tag) return True # OK def get_ref_url(self): refPath = "/by_key/%s" % self.data["key"] return compat.quote(self.provider.share_path + refPath) def get_property_names(self, is_allprop): # 让基类实现添加支持的 live 和 dead 属性 propNameList = super(VirtualResource, self).get_property_names(is_allprop) # 添加自定义实时属性(报告“allprop”和“propnames”) propNameList.extend(VirtualResource._supportedProps) return propNameList def get_property_value(self, name): #返回属性的值。参考get_property_value() # 支持的自定义实时属性 if name == "{virtres:}key": return self.data["key"] elif name == "{virtres:}title": return self.data["title"] elif name == "{virtres:}status": return self.data["status"] elif name == "{virtres:}orga": return self.data["orga"] elif name == "{virtres:}tags": # 'tags' is a string list return ",".join(self.data["tags"]) elif name == "{virtres:}description": return self.data["description"] return super(VirtualResource, self).get_property_value(name) def set_property_value(self, name, value, dry_run=False): #设置或删除属性值。 if value is None: # 将永远无法删除属性 raise DAVError(HTTP_FORBIDDEN) if name == "{virtres:}tags": # 值是 etree.Element 类型 self.data["tags"] = value.text.split(",") elif name == "{virtres:}description": # 值是 etree.Element 类型 self.data["description"] = value.text elif name in VirtualResource._supportedProps: # 受支持的属性 raise DAVError( HTTP_FORBIDDEN, err_condition=PRECONDITION_CODE_ProtectedProperty ) else: # 不受支持 raise DAVError(HTTP_FORBIDDEN) return