utils.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. #!/usr/bin/env python
  2. # -*- coding = utf-8 -*-
  3. # filename: utils.py
  4. from configparser import DEFAULTSECT, MissingSectionHeaderError, ParsingError, RawConfigParser, \
  5. NoSectionError
  6. import os
  7. import stat
  8. from mutagen._compat import StringIO
  9. from requests.compat import basestring
  10. SUFFIX = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
  11. def appromix(size, base=0):
  12. """Conver bytes stream size to human-readable format.
  13. Keyword arguments:
  14. size: int, bytes stream size
  15. base: int, suffix index
  16. Return: string
  17. """
  18. multiples = 1024
  19. if size < 0:
  20. raise ValueError('[-] Error: number must be non-negative.')
  21. if size < multiples:
  22. return '{0:d}{1}'.format(size, SUFFIX[base])
  23. for suffix in SUFFIX[base:]:
  24. if size < multiples:
  25. return '{0:.2f}{1}'.format(size, suffix)
  26. size //= multiples
  27. raise ValueError('[-] Error: number too big.')
  28. def get_file_ext_name(filename, double_ext=True):
  29. li = filename.split(os.extsep)
  30. if len(li) <= 1:
  31. return ''
  32. else:
  33. if li[-1].find(os.sep) != -1:
  34. return ''
  35. if double_ext:
  36. if len(li) > 2:
  37. if li[-2].find(os.sep) == -1:
  38. return '%s.%s' % (li[-2], li[-1])
  39. return li[-1]
  40. class Fdfs_ConfigParser(RawConfigParser):
  41. """
  42. Extends ConfigParser to allow files without sections.
  43. This is done by wrapping read files and prepending them with a placeholder
  44. section, which defaults to '__config__'
  45. """
  46. def __init__(self, default_section=None, *args, **kwargs):
  47. RawConfigParser.__init__(self, *args, **kwargs)
  48. self._default_section = None
  49. self.set_default_section(default_section or '__config__')
  50. def get_default_section(self):
  51. return self._default_section
  52. def set_default_section(self, section):
  53. self.add_section(section)
  54. # move all values from the previous default section to the new one
  55. try:
  56. default_section_items = self.items(self._default_section)
  57. self.remove_section(self._default_section)
  58. except NoSectionError:
  59. pass
  60. else:
  61. for (key, value) in default_section_items:
  62. self.set(section, key, value)
  63. self._default_section = section
  64. def read(self, filenames):
  65. if isinstance(filenames, basestring):
  66. filenames = [filenames]
  67. read_ok = []
  68. for filename in filenames:
  69. try:
  70. with open(filename) as fp:
  71. self.readfp(fp)
  72. except IOError as e:
  73. continue
  74. else:
  75. read_ok.append(filename)
  76. return read_ok
  77. def readfp(self, fp, *args, **kwargs):
  78. stream = StringIO()
  79. try:
  80. stream.name = fp.name
  81. except AttributeError as e:
  82. pass
  83. stream.write('[' + self._default_section + ']\n')
  84. stream.write(fp.read())
  85. stream.seek(0, 0)
  86. return self._read(stream, stream.name)
  87. def write(self, fp):
  88. # Write the items from the default section manually and then remove them
  89. # from the data. They'll be re-added later.
  90. try:
  91. default_section_items = self.items(self._default_section)
  92. self.remove_section(self._default_section)
  93. for (key, value) in default_section_items:
  94. fp.write("{0} = {1}\n".format(key, value))
  95. fp.write("\n")
  96. except NoSectionError:
  97. pass
  98. RawConfigParser.write(self, fp)
  99. self.add_section(self._default_section)
  100. for (key, value) in default_section_items:
  101. self.set(self._default_section, key, value)
  102. def _read(self, fp, fpname):
  103. """Parse a sectioned setup file.
  104. The sections in setup file contains a title line at the top,
  105. indicated by a name in square brackets (`[]'), plus key/value
  106. options lines, indicated by `name: value' format lines.
  107. Continuations are represented by an embedded newline then
  108. leading whitespace. Blank lines, lines beginning with a '#',
  109. and just about everything else are ignored.
  110. """
  111. cursect = None # None, or a dictionary
  112. optname = None
  113. lineno = 0
  114. e = None # None, or an exception
  115. while True:
  116. line = fp.readline()
  117. if not line:
  118. break
  119. lineno += 1
  120. # comment or blank line?
  121. if line.strip() == '' or line[0] in '#;':
  122. continue
  123. if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR":
  124. # no leading whitespace
  125. continue
  126. # continuation line?
  127. if line[0].isspace() and cursect is not None and optname:
  128. value = line.strip()
  129. if value:
  130. cursect[optname] = "%s\n%s" % (cursect[optname], value)
  131. # a section header or option header?
  132. else:
  133. # is it a section header?
  134. mo = self.SECTCRE.match(line)
  135. if mo:
  136. sectname = mo.group('header')
  137. if sectname in self._sections:
  138. cursect = self._sections[sectname]
  139. elif sectname == DEFAULTSECT:
  140. cursect = self._defaults
  141. else:
  142. cursect = self._dict()
  143. cursect['__name__'] = sectname
  144. self._sections[sectname] = cursect
  145. # So sections can't start with a continuation line
  146. optname = None
  147. # no section header in the file?
  148. elif cursect is None:
  149. raise MissingSectionHeaderError(fpname, lineno, line)
  150. # an option line?
  151. else:
  152. mo = self.OPTCRE.match(line)
  153. if mo:
  154. optname, vi, optval = mo.group('option', 'vi', 'value')
  155. if vi in ('=', ':') and ';' in optval:
  156. # ';' is a comment delimiter only if it follows
  157. # a spacing character
  158. pos = optval.find(';')
  159. if pos != -1 and optval[pos - 1].isspace():
  160. optval = optval[:pos]
  161. optval = optval.strip()
  162. # allow empty values
  163. if optval == '""':
  164. optval = ''
  165. optname = self.optionxform(optname.rstrip())
  166. if cursect.get(optname):
  167. if not isinstance(cursect[optname], list):
  168. cursect[optname] = [cursect[optname]]
  169. cursect[optname].append(optval)
  170. else:
  171. cursect[optname] = optval
  172. else:
  173. # a non-fatal parsing error occurred. set up the
  174. # exception but keep going. the exception will be
  175. # raised at the end of the file and will contain a
  176. # list of all bogus lines
  177. if not e:
  178. e = ParsingError(fpname)
  179. e.append(lineno, repr(line))
  180. # if any parsing errors occurred, raise an exception
  181. if e:
  182. raise e
  183. def split_remote_fileid(remote_file_id):
  184. """
  185. Splite remote_file_id to (group_name, remote_file_name)
  186. arguments:
  187. @remote_file_id: string
  188. @return tuple, (group_name, remote_file_name)
  189. """
  190. index = remote_file_id.find('/')
  191. if -1 == index:
  192. return None
  193. return remote_file_id[0:index], remote_file_id[(index + 1):]
  194. def fdfs_check_file(filename):
  195. ret = True
  196. errmsg = ''
  197. if not os.path.isfile(filename):
  198. ret = False
  199. errmsg = '[-] Error: %s is not a file.' % filename
  200. elif not stat.S_ISREG(os.stat(filename).st_mode):
  201. ret = False
  202. errmsg = '[-] Error: %s is not a regular file.' % filename
  203. return ret, errmsg
  204. if __name__ == '__main__':
  205. print(get_file_ext_name('/bc.tar.gz'))