PageRenderTime 35ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/data/src/file_fs/system.py

https://github.com/hivesolutions/colony_plugins
Python | 339 lines | 117 code | 68 blank | 154 comment | 14 complexity | 258a2597eec0999dfb73effe20b681ff MD5 | raw file
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. # Hive Colony Framework
  4. # Copyright (c) 2008-2020 Hive Solutions Lda.
  5. #
  6. # This file is part of Hive Colony Framework.
  7. #
  8. # Hive Colony Framework is free software: you can redistribute it and/or modify
  9. # it under the terms of the Apache License as published by the Apache
  10. # Foundation, either version 2.0 of the License, or (at your option) any
  11. # later version.
  12. #
  13. # Hive Colony Framework is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # Apache License for more details.
  17. #
  18. # You should have received a copy of the Apache License along with
  19. # Hive Colony Framework. If not, see <http://www.apache.org/licenses/>.
  20. __author__ = "João Magalhães <joamag@hive.pt>"
  21. """ The author(s) of the module """
  22. __version__ = "1.0.0"
  23. """ The version of the module """
  24. __revision__ = "$LastChangedRevision$"
  25. """ The revision number of the module """
  26. __date__ = "$LastChangedDate$"
  27. """ The last change date of the module """
  28. __copyright__ = "Copyright (c) 2008-2020 Hive Solutions Lda."
  29. """ The copyright for the module """
  30. __license__ = "Apache License, Version 2.0"
  31. """ The license for the module """
  32. import os
  33. import colony
  34. ENGINE_NAME = "fs"
  35. """ The engine name """
  36. BUFFER_SIZE = 4096
  37. """ The size of the buffer for writing, this values
  38. is relevant for the performance of that operation as
  39. a small value would imply many operations and a large
  40. value may require a large amount of memory"""
  41. class FileFS(colony.System):
  42. """
  43. The File FS class.
  44. """
  45. def get_engine_name(self):
  46. """
  47. Retrieves the name of the engine.
  48. :rtype: String
  49. :return: The name of the engine.
  50. """
  51. return ENGINE_NAME
  52. def get_internal_version(self):
  53. """
  54. Retrieves the internal database manager oriented
  55. version of the engine.
  56. :rtype: String
  57. :return: internal database manager oriented
  58. version of the engine.
  59. """
  60. return None
  61. def create_connection(self, connection_parameters):
  62. # retrieves the plugin manager
  63. plugin_manager = self.plugin.manager
  64. # retrieves the connection parameters
  65. context_name = connection_parameters.get("context_name", "default")
  66. base_path = connection_parameters.get("base_path", "%configuration:" + self.plugin.id + "%")
  67. # creates the (full) base path by appending the context name and
  68. # resolves it (for configuration directories) using the plugin manager
  69. base_path = os.path.join(base_path, context_name)
  70. base_path = plugin_manager.resolve_file_path(base_path, True, True)
  71. # creates the required (base_path) directories for the
  72. # file system persistence
  73. if not os.path.isdir(base_path): os.makedirs(base_path)
  74. # creates the (FS) connection with the given
  75. # context name and base path
  76. fs_connection = FsConnection(context_name, base_path)
  77. # returns the created (FS) connection
  78. return fs_connection
  79. def close_connection(self, connection):
  80. pass
  81. def get(self, connection, file_name):
  82. # retrieves the base file connection and
  83. # then uses it to retrieve the base path
  84. file_connection = connection.file_connection
  85. base_path = file_connection.base_path
  86. # strips the extra path separator values
  87. # (avoids problems working with the file system)
  88. file_name = file_name.lstrip("/")
  89. # creates the target file path from the base path
  90. # and then opens the target file for reading using it
  91. target_file_path = os.path.join(base_path, file_name)
  92. target_file_path = os.path.normpath(target_file_path)
  93. target_file = open(target_file_path, "rb")
  94. # returns the opened target file
  95. return target_file
  96. def delete(self, connection, file_name):
  97. # retrieves the base file connection and
  98. # then uses it to retrieve the base path
  99. file_connection = connection.file_connection
  100. base_path = file_connection.base_path
  101. # strips the extra path separator values
  102. # (avoids problems working with the file system)
  103. file_name = file_name.lstrip("/")
  104. # creates the target file path from the base path
  105. # and removes it from the file system
  106. target_file_path = os.path.join(base_path, file_name)
  107. target_file_path = os.path.normpath(target_file_path)
  108. os.remove(target_file_path)
  109. def put(self, connection, file_path, file_name):
  110. # retrieves the base file connection and
  111. # then uses it to retrieve the base path
  112. file_connection = connection.file_connection
  113. base_path = file_connection.base_path
  114. # strips the extra path separator values
  115. # (avoids problems working with the file system)
  116. file_name = file_name.lstrip("/")
  117. # retrieves the (base) file name and constructs
  118. # the complete target file path based on it
  119. target_file_path = os.path.join(base_path, file_name)
  120. target_file_path = os.path.normpath(target_file_path)
  121. # retrieves the target directory path and creates
  122. # if if it does not already exists
  123. target_directory_path = os.path.dirname(target_file_path)
  124. if not os.path.isdir(target_directory_path): os.makedirs(target_directory_path)
  125. # opens both the source and target files
  126. # for binary reading and writing
  127. source_file = open(file_path, "rb")
  128. target_file = open(target_file_path, "wb")
  129. try:
  130. # iterates continuously for file copying
  131. # (copies a chunk for each iteration)
  132. while True:
  133. # retrieves a chunk from the source file
  134. source_chunk = source_file.read(BUFFER_SIZE)
  135. # in case no source chunk could be read
  136. if not source_chunk:
  137. # breaks the loop (no more
  138. # data to be copied)
  139. break
  140. # writes the source chunk to the target
  141. # file (copy)
  142. target_file.write(source_chunk)
  143. finally:
  144. # closes the source and target files
  145. # (safe closing)
  146. source_file.close()
  147. target_file.close()
  148. def put_file(self, connection, file, file_name):
  149. # retrieves the base file connection and
  150. # then uses it to retrieve the base path
  151. file_connection = connection.file_connection
  152. base_path = file_connection.base_path
  153. # strips the extra path separator values
  154. # (avoids problems working with the file system)
  155. file_name = file_name.lstrip("/")
  156. # retrieves the (base) file name and constructs
  157. # the complete target file path based on it
  158. target_file_path = os.path.join(base_path, file_name)
  159. target_file_path = os.path.normpath(target_file_path)
  160. # retrieves the target directory path and creates
  161. # if if it does not already exists
  162. target_directory_path = os.path.dirname(target_file_path)
  163. if not os.path.isdir(target_directory_path): os.makedirs(target_directory_path)
  164. # opens target file for writing
  165. target_file = open(target_file_path, "wb")
  166. try:
  167. # iterates continuously for file copying
  168. # (copies a chunk for each iteration)
  169. while True:
  170. # retrieves a chunk from the (source) file
  171. source_chunk = file.read(BUFFER_SIZE)
  172. # in case no source chunk could be read
  173. if not source_chunk:
  174. # breaks the loop (no more
  175. # data to be copied)
  176. break
  177. # writes the source chunk to the target
  178. # file (copy)
  179. target_file.write(source_chunk)
  180. finally:
  181. # closes target file (safe closing)
  182. target_file.close()
  183. def put_data(self, connection, data, file_name):
  184. # retrieves the base file connection and
  185. # then uses it to retrieve the base path
  186. file_connection = connection.file_connection
  187. base_path = file_connection.base_path
  188. # strips the extra path separator values
  189. # (avoids problems working with the file system)
  190. file_name = file_name.lstrip("/")
  191. # retrieves the (base) file name and constructs
  192. # the complete target file path based on it
  193. target_file_path = os.path.join(base_path, file_name)
  194. target_file_path = os.path.normpath(target_file_path)
  195. # retrieves the target directory path and creates
  196. # if if it does not already exists
  197. target_directory_path = os.path.dirname(target_file_path)
  198. if not os.path.isdir(target_directory_path): os.makedirs(target_directory_path)
  199. # opens target file for writing
  200. target_file = open(target_file_path, "wb")
  201. try:
  202. # writes the data to the target
  203. # file (copy)
  204. target_file.write(data)
  205. finally:
  206. # closes target file (safe closing)
  207. target_file.close()
  208. def list(self, connection, directory_name):
  209. # retrieves the base file connection and
  210. # then uses it to retrieve the base path
  211. file_connection = connection.file_connection
  212. base_path = file_connection.base_path
  213. # strips the extra path separator values
  214. # (avoids problems working with the file system)
  215. directory_name = directory_name.lstrip("/")
  216. # creates the full directory name from the base
  217. # path and the directory name
  218. full_directory_name = os.path.join(base_path, directory_name)
  219. # list the directory entries from the directory
  220. file_name_list = os.listdir(full_directory_name)
  221. # returns the file name list
  222. return file_name_list
  223. def size(self, connection, file_name):
  224. # retrieves the base file connection and
  225. # then uses it to retrieve the base path
  226. file_connection = connection.file_connection
  227. base_path = file_connection.base_path
  228. # strips the extra path separator values
  229. # (avoids problems working with the file system)
  230. file_name = file_name.lstrip("/")
  231. # creates the target file path from the base path
  232. # and uses it to retrieve the size of the file (in bytes)
  233. target_file_path = os.path.join(base_path, file_name)
  234. target_file_path = os.path.normpath(target_file_path)
  235. return os.path.getsize(target_file_path)
  236. def mtime(self, connection, file_name):
  237. # retrieves the base file connection and
  238. # then uses it to retrieve the base path
  239. file_connection = connection.file_connection
  240. base_path = file_connection.base_path
  241. # strips the extra path separator values
  242. # (avoids problems working with the file system)
  243. file_name = file_name.lstrip("/")
  244. # creates the target file path from the base path
  245. # and uses it to retrieve the modification timestamp
  246. target_file_path = os.path.join(base_path, file_name)
  247. target_file_path = os.path.normpath(target_file_path)
  248. return os.path.getmtime(target_file_path)
  249. class FsConnection(object):
  250. """
  251. The connection that holds the information, regarding
  252. the connection to the file system (FS) engine.
  253. """
  254. context_name = None
  255. """ The name of the persistence context """
  256. base_path = None
  257. """ The base path used for the persistence
  258. for the files in the file system """
  259. def __init__(self, context_name, base_path):
  260. """
  261. Constructor of the class.
  262. :type context_name: String
  263. :param context_name: The name of the persistence context.
  264. :type base_path: String
  265. :param base_path: The base path for persistence.
  266. """
  267. self.context_name = context_name
  268. self.base_path = base_path