KApiDox

utils.py
1 # -*- coding: utf-8 -*-
2 #
3 # SPDX-FileCopyrightText: 2014 Aurélien Gâteau <[email protected]>
4 #
5 # SPDX-License-Identifier: BSD-2-Clause
6 
7 from fnmatch import fnmatch
8 import logging
9 import os
10 import re
11 import subprocess
12 import shutil
13 import sys
14 import tempfile
15 import requests
16 
17 ## @package kapidox.utils
18 #
19 # Multiple usage utils.
20 #
21 # This module contains code which is shared between depdiagram-prepare and
22 # other components.
23 #
24 # Code in this dir should not import any module which is not shipped with
25 # Python because this module is used by depdiagram-prepare, which must be able
26 # to run on builds.kde.org, which may not have all the required dependencies.
27 #
28 
29 def setup_logging():
30  FORMAT = '%(asctime)s %(levelname)s %(message)s'
31  logging.basicConfig(format=FORMAT, datefmt='%H:%M:%S', level=logging.DEBUG)
32 
33 
34 def tolist(a):
35  """ Return a list based on `a`. """
36  return a if type(a) is list else [a]
37 
38 
39 def serialize_name(name):
40  """ Return a serialized name.
41 
42  For now it only replaces ' ' with '_' and lower the letters.
43  """
44  if name is not None:
45  return '_'.join(name.lower().split(' '))
46  else:
47  return None
48 
49 def set_repopath(id):
50  """ Return the repopath for the repo id, queried from projects.kde.org
51 
52  Args:
53  id: unique KDE repo identifier
54  """
55  if id is None:
56  return None
57 
58  try:
59  r = requests.get('https://projects.kde.org/api/v1/identifier/' + id)
60  return r.json()['repo']
61  except Exception as exc:
62  # Catch all exceptions here: whatever fails in this function should not
63  # cause the code to fail
64  logging.warning("Failed to get repository url for '{}' from projects.kde.org: {}".format(id, exc))
65  return None
66 
67 def set_maintainers(maintainer_keys, all_maintainers):
68  """ Expend the name of the maintainers.
69 
70  Args:
71  dictionary: (dict) Dictionary from which the name to expend will be read.
72  key: (string) Key of the dictionary where the name to expend is saved.
73  all_maintainers: (dict of dict) Look-up table where the names and emails of
74  the maintainers are stored.
75 
76  Examples:
77  >>> maintainer_keys = ['arthur', 'toto']
78 
79  >>> myteam = {'arthur': {'name': 'Arthur Pendragon',
80  'email': '[email protected]'},
81  'toto': {'name': 'Toto',
82  'email: '[email protected]'}
83  }
84 
85  >>> set_maintainers(maintainer_keys, my_team)
86  """
87 
88  if not maintainer_keys:
89  maintainers = []
90  elif isinstance(maintainer_keys, list):
91  maintainers = map(lambda x: all_maintainers.get(x, None),
92  maintainer_keys)
93  else:
94  maintainers = [all_maintainers.get(maintainer_keys, None)]
95 
96  maintainers = [x for x in maintainers if x is not None]
97  return maintainers
98 
99 
100 def parse_fancyname(fw_dir):
101  """Return the framework name for a given source dir
102 
103  The framework name is the name of the toplevel CMake project
104  """
105  cmakelists_path = os.path.join(fw_dir, "CMakeLists.txt")
106  if not os.path.exists(cmakelists_path):
107  logging.error("No CMakeLists.txt in {}".format(fw_dir))
108  return None
109  project_re = re.compile(r"project\s*\(\s*([\w\-\_]+)", re.I)
110  with open(cmakelists_path) as f:
111  for line in f.readlines():
112  match = project_re.search(line)
113  if match:
114  return match.group(1)
115  logging.error("Failed to find framework name: Could not find a "
116  "'project()' command in {}.".format(cmakelists_path))
117  return None
118 
119 
120 def cache_dir():
121  """Find/create a semi-long-term cache directory.
122 
123  We do not use tempdir, except as a fallback, because temporary directories
124  are intended for files that only last for the program's execution.
125  """
126  cachedir = None
127  if sys.platform == 'darwin':
128  try:
129  from AppKit import NSSearchPathForDirectoriesInDomains
130  # http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/c/func/NSSearchPathForDirectoriesInDomains
131  # NSApplicationSupportDirectory = 14
132  # NSUserDomainMask = 1
133  # True for expanding the tilde into a fully qualified path
134  cachedir = os.path.join(
135  NSSearchPathForDirectoriesInDomains(14, 1, True)[0],
136  'KApiDox')
137  except:
138  pass
139  elif os.name == "posix":
140  if 'HOME' in os.environ and os.path.exists(os.environ['HOME']):
141  cachedir = os.path.join(os.environ['HOME'], '.cache', 'kapidox')
142  elif os.name == "nt":
143  if 'APPDATA' in os.environ and os.path.exists(os.environ['APPDATA']):
144  cachedir = os.path.join(os.environ['APPDATA'], 'KApiDox')
145  if cachedir is None:
146  cachedir = os.path.join(tempfile.gettempdir(), 'kapidox')
147  if not os.path.isdir(cachedir):
148  os.makedirs(cachedir)
149  return cachedir
150 
151 
152 def svn_export(remote, local, overwrite=False):
153  """Wraps svn export.
154 
155  Args:
156  remote: (string) the remote url.
157  local: (string) the local path where to dowload.
158  overwrite: (bool) whether to overwrite `local` or not. (optional,
159  default = False)
160 
161  Returns:
162  True if success.
163 
164  Raises:
165  FileNotFoundError: &nbsp;
166  subprocess.CalledProcessError: &nbsp;
167  """
168  try:
169  import svn.core
170  import svn.client
171  logging.debug("Using Python libsvn bindings to fetch %s", remote)
172  ctx = svn.client.create_context()
173  ctx.auth_baton = svn.core.svn_auth_open([])
174 
175  latest = svn.core.svn_opt_revision_t()
176  latest.type = svn.core.svn_opt_revision_head
177 
178  svn.client.export(remote, local, latest, True, ctx)
179  except ImportError:
180  logging.debug("Using external svn client to fetch %s", remote)
181  cmd = ['svn', 'export', '--quiet']
182  if overwrite:
183  cmd.append('--force')
184  cmd += [remote, local]
185  try:
186  subprocess.check_call(cmd, stderr=subprocess.STDOUT)
187  except subprocess.CalledProcessError as e:
188  raise subprocess.StandardException(e.output)
189  except FileNotFoundError as e:
190  logging.debug("External svn client not found")
191  return False
192  # subversion will set the timestamp to match the server
193  os.utime(local, None)
194  return True
195 
196 
197 def copy_dir_contents(directory, dest):
198  """Copy the contents of a directory
199 
200  Args:
201  directory: (string) the directory to copy the contents of.
202  dest: (string) the directory to copy them into.
203  """
204  ignored = ['CMakeLists.txt']
205  ignore = shutil.ignore_patterns(*ignored)
206  for fn in os.listdir(directory):
207  f = os.path.join(directory, fn)
208  if os.path.isfile(f):
209  docopy = True
210  for i in ignored:
211  if fnmatch(fn, i):
212  docopy = False
213  break
214  if docopy:
215  shutil.copy(f, dest)
216  elif os.path.isdir(f):
217  dest_f = os.path.join(dest, fn)
218  if os.path.isdir(dest_f):
219  shutil.rmtree(dest_f)
220  shutil.copytree(f, dest_f, ignore=ignore)
221 
222 
223 _KAPIDOX_VERSION = None
224 def get_kapidox_version():
225  """Get commit id of running code if it is running from git repository.
226 
227  May return an empty string if it failed to extract the commit id.
228 
229  Assumes .git/HEAD looks like this:
230 
231  ref: refs/heads/master
232 
233  and assumes .git/refs/heads/master contains the commit id
234  """
235  global _KAPIDOX_VERSION
236 
237  if _KAPIDOX_VERSION is not None:
238  return _KAPIDOX_VERSION
239 
240  _KAPIDOX_VERSION = ""
241  bin_dir = os.path.dirname(sys.argv[0])
242  git_dir = os.path.join(bin_dir, "..", ".git")
243  if not os.path.isdir(git_dir):
244  # Looks like we are not running from the git repo, exit silently
245  return _KAPIDOX_VERSION
246 
247  git_HEAD = os.path.join(git_dir, "HEAD")
248  if not os.path.isfile(git_HEAD):
249  logging.warning("Getting git info failed: {} is not a file".format(git_HEAD))
250  return _KAPIDOX_VERSION
251 
252  try:
253  line = open(git_HEAD).readline()
254  ref_name = line.split(": ")[1].strip()
255  with open(os.path.join(git_dir, ref_name)) as f:
256  _KAPIDOX_VERSION = f.read().strip()
257  except Exception as exc:
258  # Catch all exceptions here: whatever fails in this function should not
259  # cause the code to fail
260  logging.warning("Getting git info failed: {}".format(exc))
261  return _KAPIDOX_VERSION
262 
263 
264 def find_dot_files(dot_dir):
265  """Returns a list of path to files ending with .dot in subdirs of `dot_dir`."""
266  lst = []
267  for (root, dirs, files) in os.walk(dot_dir):
268  lst.extend([os.path.join(root, x) for x in files if x.endswith('.dot')])
269  return lst
def serialize_name(name)
Return a serialized name.
Definition: utils.py:43
def parse_fancyname(fw_dir)
Return the framework name for a given source dir.
Definition: utils.py:108
def find_dot_files(dot_dir)
Returns a list of path to files ending with .dot in subdirs of dot_dir.
Definition: utils.py:278
def set_repopath(id)
Return the repopath for the repo id, queried from projects.kde.org.
Definition: utils.py:54
def tolist(a)
Return a list based on a.
Definition: utils.py:35
def cache_dir()
Find/create a semi-long-term cache directory.
Definition: utils.py:129
def svn_export(remote, local, overwrite=False)
Wraps svn export.
Definition: utils.py:171
def get_kapidox_version()
Get commit id of running code if it is running from git repository.
Definition: utils.py:241
def set_maintainers(maintainer_keys, all_maintainers)
Expend the name of the maintainers.
Definition: utils.py:90
def copy_dir_contents(directory, dest)
Copy the contents of a directory.
Definition: utils.py:207
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Jan 19 2021 22:56:16 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.