fb-tools 3.2.1__tar.gz → 3.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. {fb_tools-3.2.1 → fb_tools-3.3.0}/PKG-INFO +1 -1
  2. fb_tools-3.3.0/data/share/locale/de/LC_MESSAGES/fb_tools.mo +0 -0
  3. fb_tools-3.3.0/data/share/locale/en/LC_MESSAGES/fb_tools.mo +0 -0
  4. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/__init__.py +3 -1
  5. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/application/get_file_rm.py +26 -15
  6. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/handling_obj.py +225 -10
  7. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/multi_config/inits.py +57 -37
  8. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/socket_obj/__init__.py +7 -3
  9. fb_tools-3.2.1/data/share/locale/de/LC_MESSAGES/fb_tools.mo +0 -0
  10. fb_tools-3.2.1/data/share/locale/en/LC_MESSAGES/fb_tools.mo +0 -0
  11. {fb_tools-3.2.1 → fb_tools-3.3.0}/LICENSE +0 -0
  12. {fb_tools-3.2.1 → fb_tools-3.3.0}/README.md +0 -0
  13. {fb_tools-3.2.1 → fb_tools-3.3.0}/pyproject.toml +0 -0
  14. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/any_config.py +0 -0
  15. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/app.py +0 -0
  16. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/application/__init__.py +0 -0
  17. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/application/cfg_converter.py +0 -0
  18. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/application/show_spinner.py +0 -0
  19. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/argparse_actions.py +0 -0
  20. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/cfg_app.py +0 -0
  21. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/cfg_options/__init__.py +0 -0
  22. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/cfg_options/dump.py +0 -0
  23. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/cfg_options/hjson.py +0 -0
  24. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/cfg_options/inifile.py +0 -0
  25. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/cfg_options/json.py +0 -0
  26. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/cfg_options/toml.py +0 -0
  27. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/cfg_options/yaml.py +0 -0
  28. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/colcts.py +0 -0
  29. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/collections.py +0 -0
  30. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/common.py +0 -0
  31. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/config.py +0 -0
  32. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/errors.py +0 -0
  33. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/handler/__init__.py +0 -0
  34. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/handler/lock.py +0 -0
  35. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/mailaddress.py +0 -0
  36. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/merge.py +0 -0
  37. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/multi_config/__init__.py +0 -0
  38. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/multi_config/files.py +0 -0
  39. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/obj.py +0 -0
  40. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/pidfile.py +0 -0
  41. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/socket_obj/tcp.py +0 -0
  42. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/socket_obj/unix.py +0 -0
  43. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/spinner.py +0 -0
  44. {fb_tools-3.2.1 → fb_tools-3.3.0}/src/fb_tools/xlate.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fb_tools
3
- Version: 3.2.1
3
+ Version: 3.3.0
4
4
  Summary: @summary: A module for common used objects, error classes and functions.
5
5
  Author-email: Frank Brehm <frank@brehm-online.com>
6
6
  Requires-Python: >=3.8
@@ -27,11 +27,13 @@ MIN_INDENT = 2
27
27
  # Maximal indention of configuration files
28
28
  MAX_INDENT = 12
29
29
 
30
+ PROJECT_NAME = "fb-tools"
31
+
30
32
  # Own modules
31
33
 
32
34
  from .mailaddress import MailAddress, MailAddressList, QualifiedMailAddress # noqa: F401
33
35
  from .multi_config import BaseMultiConfig # noqa: F401
34
36
 
35
- __version__ = "3.2.1"
37
+ __version__ = "3.3.0"
36
38
 
37
39
  # vim: ts=4 et list
@@ -29,7 +29,7 @@ from ..common import get_monday, pp
29
29
  from ..errors import FbAppError
30
30
  from ..xlate import XLATOR
31
31
 
32
- __version__ = "2.2.1"
32
+ __version__ = "2.2.2"
33
33
  LOG = logging.getLogger(__name__)
34
34
 
35
35
  _ = XLATOR.gettext
@@ -171,8 +171,10 @@ class GetFileRmApplication(BaseApplication):
171
171
  if v >= self.min_keep_days:
172
172
  self._keep_days = v
173
173
  else:
174
- msg = _("Wrong value {v!r} for {n}, must be >= {m}").format(
175
- v=value, n="keep_days", m=self.min_keep_days
174
+ msg = _("Wrong value {v} for {n}, must be >= {m}").format(
175
+ v=self.colored(repr(value), "red"),
176
+ n="keep_days",
177
+ m=self.colored(str(self.min_keep_days), "yellow"),
176
178
  )
177
179
  raise ValueError(msg)
178
180
 
@@ -188,8 +190,10 @@ class GetFileRmApplication(BaseApplication):
188
190
  if v >= self.min_keep_weeks:
189
191
  self._keep_weeks = v
190
192
  else:
191
- msg = _("Wrong value {v!r} for {n}, must be >= {m}").format(
192
- v=value, n="keep_weeks", m=self.min_keep_weeks
193
+ msg = _("Wrong value {v} for {n}, must be >= {m}").format(
194
+ v=self.colored(repr(value), "red"),
195
+ n="keep_weeks",
196
+ m=self.colored(str(self.min_keep_weeks), "yellow"),
193
197
  )
194
198
  raise ValueError(msg)
195
199
 
@@ -205,8 +209,10 @@ class GetFileRmApplication(BaseApplication):
205
209
  if v >= self.min_keep_months:
206
210
  self._keep_months = v
207
211
  else:
208
- msg = _("Wrong value {v!r} for {n}, must be >= {m}").format(
209
- v=value, n="keep_months", m=self.min_keep_months
212
+ msg = _("Wrong value {v} for {n}, must be >= {m}").format(
213
+ v=self.colored(repr(value), "red"),
214
+ n="keep_months",
215
+ m=self.colored(str(self.min_keep_months), "yellow"),
210
216
  )
211
217
  raise ValueError(msg)
212
218
 
@@ -222,8 +228,10 @@ class GetFileRmApplication(BaseApplication):
222
228
  if v >= self.min_keep_years:
223
229
  self._keep_years = v
224
230
  else:
225
- msg = _("Wrong value {v!r} for {n}, must be >= {m}").format(
226
- v=value, n="keep_years", m=self.min_keep_years
231
+ msg = _("Wrong value {v} for {n}, must be >= {m}").format(
232
+ v=self.colored(repr(value), "red"),
233
+ n="keep_years",
234
+ m=self.colored(str(self.min_keep_years), "yellow"),
227
235
  )
228
236
  raise ValueError(msg)
229
237
 
@@ -239,8 +247,10 @@ class GetFileRmApplication(BaseApplication):
239
247
  if v >= self.min_keep_last:
240
248
  self._keep_last = v
241
249
  else:
242
- msg = _("Wrong value {v!r} for {n}, must be >= {m}").format(
243
- v=value, n="keep_last", m=self.min_keep_last
250
+ msg = _("Wrong value {v} for {n}, must be >= {m}").format(
251
+ v=self.colored(repr(value), "red"),
252
+ n="keep_last",
253
+ m=self.colored(str(self.min_keep_last), "yellow"),
244
254
  )
245
255
  raise ValueError(msg)
246
256
 
@@ -368,7 +378,7 @@ class GetFileRmApplication(BaseApplication):
368
378
  if not check_date_pattern(pat):
369
379
  raise WrongDatePattern(self.date_pattern)
370
380
  if self.verbose > 1:
371
- LOG.debug(_("Resolving date pattern {!r}.").format(pat))
381
+ LOG.debug(_("Resolving date pattern {}.").format(self.colored(pat, "cyan")))
372
382
 
373
383
  self._pattern = (
374
384
  pat.replace("%Y", r"(?P<year>\d{4})")
@@ -395,7 +405,7 @@ class GetFileRmApplication(BaseApplication):
395
405
  for fname in self.args.files:
396
406
 
397
407
  if self.verbose > 2:
398
- LOG.debug(_("Checking given file {!r} ...").format(fname))
408
+ LOG.debug(_("Checking given file {} ...").format(self.colored(fname, "cyan")))
399
409
 
400
410
  given_paths = []
401
411
  single_fpath = Path(fname)
@@ -429,8 +439,9 @@ class GetFileRmApplication(BaseApplication):
429
439
  match = self.re_date.search(str(fpath))
430
440
  if not match:
431
441
  LOG.warning(
432
- _("File {fi!r} does not match pattern {pa!r}.").format(
433
- fi=str(fpath), pa=self.date_pattern
442
+ _("File {fi} does not match pattern {pa}.").format(
443
+ fi=self.colored(str(fpath), "yellow"),
444
+ pa=self.colord(repr(self.date_pattern), "yellow"),
434
445
  )
435
446
  )
436
447
  continue
@@ -24,17 +24,13 @@ import shutil
24
24
  import signal
25
25
  import socket
26
26
  import sys
27
+ from pathlib import Path
27
28
  from shlex import quote
28
29
  from subprocess import PIPE, Popen
29
30
 
30
31
  # from codecs import BOM_BE, BOM_LE, BOM_UTF32_BE, BOM_UTF32_LE, BOM_UTF8
31
32
  # from collections import OrderedDict
32
33
 
33
- try:
34
- import pathlib
35
- except ImportError:
36
- import pathlib2 as pathlib
37
-
38
34
  if sys.version_info[0] >= 3:
39
35
  from subprocess import SubprocessError, TimeoutExpired
40
36
  else:
@@ -57,6 +53,7 @@ import six
57
53
 
58
54
  # Own modules
59
55
  from . import DEFAULT_TERMINAL_HEIGHT, DEFAULT_TERMINAL_WIDTH
56
+ from . import PROJECT_NAME
60
57
  from .common import caller_search_path, encode_or_bust, pp, to_bool, to_str
61
58
  from .common import indent, is_sequence
62
59
  from .errors import AbortAppError
@@ -69,7 +66,7 @@ from .errors import WriteTimeoutError
69
66
  from .obj import FbBaseObject
70
67
  from .xlate import XLATOR, format_list
71
68
 
72
- __version__ = "2.4.9"
69
+ __version__ = "2.6.0"
73
70
  LOG = logging.getLogger(__name__)
74
71
 
75
72
  _ = XLATOR.gettext
@@ -182,19 +179,23 @@ class HandlingObject(FbBaseObject):
182
179
  * appname (str - rw) (inherited from FbBaseObject)
183
180
  * assumed_answer (None or bool - rw)
184
181
  * base_dir (pathlib.Path - rw) (inherited from FbBaseObject)
182
+ * cache_dir (pathlib.Path - rw)
183
+ * data_dir (pathlib.Path - rw)
185
184
  * force (bool - rw)
186
185
  * initialized (bool - rw) (inherited from FbBaseObject)
187
186
  * interrupted (bool - rw)
188
187
  * is_venv (bool - ro)
188
+ * project_name (str) - rw)
189
189
  * prompt_timeout (int - rw)
190
190
  * quiet (bool - rw)
191
191
  * simulate (bool - rw)
192
+ * state_dir (pathlib.Path - rw)
192
193
  * terminal_has_colors (bool - rw)
193
194
  * verbose (int - rw) (inherited from FbBaseObject)
194
195
  * version (str - ro) (inherited from FbBaseObject)
195
196
 
196
197
  Public attributes:
197
- * add_search_paths Array of pathlib.Path
198
+ * add_search_paths Array of Path
198
199
  * signals_dont_interrupt Array of int
199
200
  """
200
201
 
@@ -221,6 +222,12 @@ class HandlingObject(FbBaseObject):
221
222
  "6",
222
223
  )
223
224
 
225
+ # Project name, used for the subdirectory name of different default directories
226
+ # e.g. log directory, data directory, cache dir, runtime dir a.s.o.
227
+ default_project_name = PROJECT_NAME
228
+
229
+ re_project_name = re.compile(r"^[a-z0-9]([a-z0-9+\-_\.]*[a-z0-9])?$", re.IGNORECASE)
230
+
224
231
  # -------------------------------------------------------------------------
225
232
  def __init__(
226
233
  self,
@@ -230,6 +237,11 @@ class HandlingObject(FbBaseObject):
230
237
  simulate=None,
231
238
  force=None,
232
239
  assumed_answer=None,
240
+ project_name=None,
241
+ data_dir=None,
242
+ cache_dir=None,
243
+ state_dir=None,
244
+ runtime_dir=None,
233
245
  *args,
234
246
  **kwargs,
235
247
  ):
@@ -248,11 +260,22 @@ class HandlingObject(FbBaseObject):
248
260
  @type: bool
249
261
  @param assumed_answer: The assumed answer to all yes/no questions.
250
262
  @type: bool or None
263
+ @param project_name: Project name used for subdirectories in default directories
264
+ @type: str
265
+ @param data_dir: directory to which user-specific data files should be stored.
266
+ @type: Path or None
267
+ @param cache_dir: directory to which user-specific non-essential data files
268
+ should be stored.
269
+ @type: Path or None
270
+ @param state_dir: directory to which user-specific state files should be stored.
271
+ @type: Path or None
272
+ @param runtime_dir: directory to which non-essential runtime files should be stored.
273
+ @type: Path or None
251
274
 
252
275
  @param appname: name of the current running application
253
276
  @type: str
254
277
  @param base_dir: base directory used for different purposes
255
- @type: str or pathlib.Path
278
+ @type: str or Path
256
279
  @param initialized: initialisation of this object is complete after init
257
280
  @type: bool
258
281
  @param verbose: verbosity level (0 - 9)
@@ -266,10 +289,19 @@ class HandlingObject(FbBaseObject):
266
289
  self._assumed_answer = None
267
290
  self._address_family = self.default_address_family
268
291
 
292
+ self._project_name = self.default_project_name
293
+ if project_name:
294
+ self.project_name = project_name
295
+
296
+ self._data_dir = self.get_default_data_dir() / self.project_name
297
+ self._cache_dir = self.get_default_cache_dir() / self.project_name
298
+ self._state_dir = self.get_default_state_dir() / self.project_name
299
+ self._runtime_dir = self.get_default_runtime_dir() / self.project_name
300
+
269
301
  self.add_search_paths = []
270
302
  """
271
303
  @ivar: Additional search paths of executing external commands
272
- @type: Array of pathlib.Path
304
+ @type: Array of Path
273
305
  """
274
306
 
275
307
  self._prompt_timeout = self.default_prompt_timeout
@@ -292,6 +324,14 @@ class HandlingObject(FbBaseObject):
292
324
  version=version,
293
325
  **kwargs,
294
326
  )
327
+ if data_dir:
328
+ self._data_dir = data_dir
329
+ if cache_dir:
330
+ self.cache_dir = cache_dir
331
+ if state_dir:
332
+ self.state_dir = state_dir
333
+ if runtime_dir:
334
+ self.runtime_dir = runtime_dir
295
335
 
296
336
  if simulate is not None:
297
337
  self.simulate = simulate
@@ -427,6 +467,102 @@ class HandlingObject(FbBaseObject):
427
467
  family = socket.AF_INET6
428
468
  self._address_family = family
429
469
 
470
+ # -----------------------------------------------------------
471
+ @property
472
+ def project_name(self):
473
+ """Return the project name used for subdirectories in default directories."""
474
+ return self._project_name
475
+
476
+ @project_name.setter
477
+ def project_name(self, value):
478
+ if value is None:
479
+ self._project_name = self.default_project_name
480
+ return
481
+
482
+ val = str(value)
483
+ if val == "":
484
+ raise ValueError(_("A project name must not be empty."))
485
+
486
+ if not self.re_project_name.match(val):
487
+ msg = _("Invalid project name {} given.").format(self.colored(val, "red"))
488
+ raise ValueError(msg)
489
+
490
+ # -----------------------------------------------------------
491
+ @property
492
+ def data_dir(self):
493
+ """Return the directory to which user-specific data files should be stored."""
494
+ return self._data_dir
495
+
496
+ @data_dir.setter
497
+ def data_dir(self, value):
498
+ if value is None:
499
+ self._data_dir = self.get_default_data_dir() / self.project_name
500
+ return
501
+
502
+ path = Path(value)
503
+ if path.is_absolute():
504
+ self._data_dir = path
505
+ return
506
+
507
+ self._data_dir = path.resolve()
508
+
509
+ # -----------------------------------------------------------
510
+ @property
511
+ def cache_dir(self):
512
+ """Return the dir to which user-specific non-essential data files should be stored."""
513
+ return self._cache_dir
514
+
515
+ @cache_dir.setter
516
+ def cache_dir(self, value):
517
+ if value is None:
518
+ self._cache_dir = self.get_default_cache_dir() / self.project_name
519
+ return
520
+
521
+ path = Path(value)
522
+ if path.is_absolute():
523
+ self._cache_dir = path
524
+ return
525
+
526
+ self._cache_dir = path.resolve()
527
+
528
+ # -----------------------------------------------------------
529
+ @property
530
+ def state_dir(self):
531
+ """Return the directory to which user-specific state files should be stored."""
532
+ return self._state_dir
533
+
534
+ @state_dir.setter
535
+ def state_dir(self, value):
536
+ if value is None:
537
+ self._state_dir = self.get_default_state_dir() / self.project_name
538
+ return
539
+
540
+ path = Path(value)
541
+ if path.is_absolute():
542
+ self._state_dir = path
543
+ return
544
+
545
+ self._state_dir = path.resolve()
546
+
547
+ # -----------------------------------------------------------
548
+ @property
549
+ def runtime_dir(self):
550
+ """Return the directory to which user-specific runtime files should be stored."""
551
+ return self._runtime_dir
552
+
553
+ @runtime_dir.setter
554
+ def runtime_dir(self, value):
555
+ if value is None:
556
+ self._runtime_dir = self.get_default_runtime_dir() / self.project_name
557
+ return
558
+
559
+ path = Path(value)
560
+ if path.is_absolute():
561
+ self._runtime_dir = path
562
+ return
563
+
564
+ self._runtime_dir = path.resolve()
565
+
430
566
  # -------------------------------------------------------------------------
431
567
  @classmethod
432
568
  def init_yes_no_lists(cls):
@@ -450,6 +586,80 @@ class HandlingObject(FbBaseObject):
450
586
  )
451
587
  cls.re_yes_no = re.compile(cls.pattern_yes_no, re.IGNORECASE)
452
588
 
589
+ # -------------------------------------------------------------------------
590
+ @classmethod
591
+ def get_default_data_dir(cls):
592
+ """Return the default base path to the data directory."""
593
+ xdg_dir = os.environ.get("XDG_DATA_HOME", None)
594
+ xdg_dirs = os.environ.get("XDG_DATA_DIRS", None)
595
+
596
+ if xdg_dirs:
597
+ xdg_dirs = [Path(x) for x in xdg_dirs.split(os.pathsep)]
598
+ else:
599
+ xdg_dirs = []
600
+
601
+ # If $XDG_DATA_HOME was given, then use it, no matter whether it exists
602
+ if xdg_dir:
603
+ # LOG.debug(f"Using data_dir {xdg_dir!r}.")
604
+ return Path(xdg_dir)
605
+
606
+ # Search for the first existing dir in XDG_DATA_DIRS. If not existing,
607
+ # use the first one, no matter whether it exists
608
+ if xdg_dirs:
609
+ for ddir in xdg_dirs:
610
+ # LOG.debug(f"Checking data_dir {str(ddir)!r}.")
611
+ if ddir.exists and ddir.is_dir() and os.access(str(ddir), os.W_OK):
612
+ # LOG.debug(f"Using data_dir {str(ddir)!r}.")
613
+ return ddir
614
+ if not os.geteuid():
615
+ return xdg_dirs[0]
616
+
617
+ # Init as root user
618
+ if not os.geteuid():
619
+ return Path("/var/lib")
620
+
621
+ # Init as non root user
622
+ return Path("~/.local/share").expanduser()
623
+
624
+ # -------------------------------------------------------------------------
625
+ @classmethod
626
+ def get_default_cache_dir(cls):
627
+ """Get the default base path to the cache directory."""
628
+ xdg_dir = os.environ.get("XDG_CACHE_HOME", None)
629
+
630
+ if xdg_dir:
631
+ return Path(xdg_dir)
632
+
633
+ if not os.geteuid():
634
+ return Path("/var/cache")
635
+
636
+ return Path("~/.cache").expanduser()
637
+
638
+ # -------------------------------------------------------------------------
639
+ @classmethod
640
+ def get_default_state_dir(cls):
641
+ """Get the default base path to the state directory."""
642
+ xdg_dir = os.environ.get("XDG_STATE_HOME", None)
643
+
644
+ if xdg_dir:
645
+ return Path(xdg_dir)
646
+
647
+ if not os.geteuid():
648
+ return Path("/var/lib")
649
+
650
+ return Path("~/.local/state").expanduser()
651
+
652
+ # -------------------------------------------------------------------------
653
+ @classmethod
654
+ def get_default_runtime_dir(cls):
655
+ """Get the default base path to the runtime directory."""
656
+ xdg_dir = os.environ.get("XDG_RUNTIME_DIR", None)
657
+
658
+ if xdg_dir:
659
+ return Path(xdg_dir)
660
+
661
+ return Path("/run")
662
+
453
663
  # -------------------------------------------------------------------------
454
664
  def as_dict(self, short=True):
455
665
  """
@@ -464,15 +674,20 @@ class HandlingObject(FbBaseObject):
464
674
  res = super(HandlingObject, self).as_dict(short=short)
465
675
  res["address_family"] = self.address_family
466
676
  res["assumed_answer"] = self.assumed_answer
677
+ res["cache_dir"] = self.cache_dir
678
+ res["data_dir"] = self.data_dir
467
679
  res["fileio_timeout"] = self.fileio_timeout
468
680
  res["force"] = self.force
469
681
  res["interrupted"] = self.interrupted
470
682
  res["is_venv"] = self.is_venv
471
683
  res["no_list"] = self.no_list
472
684
  res["pattern_yes_no"] = self.pattern_yes_no
685
+ res["project_name"] = self.project_name
473
686
  res["prompt_timeout"] = self.prompt_timeout
474
687
  res["quiet"] = self.quiet
688
+ res["runtime_dir"] = self.runtime_dir
475
689
  res["simulate"] = self.simulate
690
+ res["state_dir"] = self.state_dir
476
691
  res["terminal_has_colors"] = self.terminal_has_colors
477
692
  res["yes_list"] = self.yes_list
478
693
 
@@ -637,7 +852,7 @@ class HandlingObject(FbBaseObject):
637
852
  @rtype: str or None
638
853
 
639
854
  """
640
- cmd = pathlib.Path(cmd)
855
+ cmd = Path(cmd)
641
856
 
642
857
  if self.verbose > 2:
643
858
  LOG.debug(_("Searching for command {!r} ...").format(str(cmd)))
@@ -25,7 +25,7 @@ import six
25
25
  from ..common import is_sequence, to_str
26
26
  from ..xlate import XLATOR
27
27
 
28
- __version__ = "0.2.1"
28
+ __version__ = "0.4.0"
29
29
 
30
30
  LOG = logging.getLogger(__name__)
31
31
 
@@ -43,54 +43,74 @@ class MultiCfgInitMixin:
43
43
 
44
44
  # -------------------------------------------------------------------------
45
45
  def _init_config_dirs(self, additional_cfgdirs=None):
46
-
46
+ """Create the list of possible configuration directories."""
47
47
  self.config_dirs = []
48
48
 
49
- self.config_dirs.append(Path("/etc") / self.config_dir)
49
+ # Insert in this list possible paths in decreasing priority
50
50
 
51
- path = Path(os.path.expanduser("~")) / ".config" / self.config_dir
52
- if path in self.config_dirs:
53
- self.config_dirs.remove(path)
51
+ # Exceptionally given additional config directory or directories
52
+ if additional_cfgdirs:
53
+ if is_sequence(additional_cfgdirs):
54
+ for item in additional_cfgdirs:
55
+ path = Path(item)
56
+ if path not in self.config_dirs:
57
+ self.config_dirs.append(path)
58
+ else:
59
+ path = Path(additional_cfgdirs)
60
+ self.config_dirs.append(Path(additional_cfgdirs))
54
61
 
55
- self.config_dirs.append(path)
56
- if self.is_venv():
57
- path = Path(sys.prefix) / "etc"
58
- if path in self.config_dirs:
59
- self.config_dirs.remove(path)
62
+ # Current working directory
63
+ path = Path.cwd()
64
+ if path not in self.config_dirs:
60
65
  self.config_dirs.append(path)
61
66
 
62
- path = Path.cwd() / "etc"
63
- if path in self.config_dirs:
64
- self.config_dirs.remove(path)
65
- self.config_dirs.append(path)
67
+ # The base directory itselv (whatever it is)
68
+ path = self.base_dir
69
+ if path not in self.config_dirs:
70
+ self.config_dirs.append(path)
66
71
 
72
+ # ${base_dir}/etc
67
73
  path = self.base_dir / "etc"
68
- if path in self.config_dirs:
69
- self.config_dirs.remove(path)
70
- self.config_dirs.append(path)
74
+ if path not in self.config_dirs:
75
+ self.config_dirs.append(path)
71
76
 
72
- path = self.base_dir
73
- if path in self.config_dirs:
74
- self.config_dirs.remove(path)
75
- self.config_dirs.append(path)
77
+ # ${current_working_directory}/etc
78
+ path = Path.cwd() / "etc"
79
+ if path not in self.config_dirs:
80
+ self.config_dirs.append(path)
76
81
 
77
- path = Path.cwd()
78
- if path in self.config_dirs:
79
- self.config_dirs.remove(path)
80
- self.config_dirs.append(path)
82
+ # ${virtual_env_directory}/etc
83
+ if self.is_venv():
84
+ path = Path(sys.prefix) / "etc"
85
+ if path not in self.config_dirs:
86
+ self.config_dirs.append(path)
81
87
 
82
- if additional_cfgdirs:
83
- if is_sequence(additional_cfgdirs):
84
- for item in additional_cfgdirs:
85
- path = Path(item)
86
- if path in self.config_dirs:
87
- self.config_dirs.remove(path)
88
+ # ${XDG_CONFIG_HOME}/${config_dir}
89
+ xdg_dir = os.environ.get("XDG_CONFIG_HOME", None)
90
+ if xdg_dir:
91
+ path = Path(xdg_dir) / self.config_dir
92
+ else:
93
+ path = Path("~/.config").expanduser() / self.config_dir
94
+ if path not in self.config_dirs:
95
+ self.config_dirs.append(path)
96
+
97
+ # All directories in $XDG_CONFIG_DIRS, appended by ${config_dir}
98
+ xdg_dirs = os.environ.get("XDG_CONFIG_DIRS", None)
99
+ if xdg_dirs:
100
+ xdg_dirs = [Path(x) for x in xdg_dirs.split(os.pathsep)]
101
+ for path in xdg_dirs:
102
+ path = path / self.config_dir
103
+ if path not in self.config_dirs:
88
104
  self.config_dirs.append(path)
89
- else:
90
- path = Path(additional_cfgdirs)
91
- if path in self.config_dirs:
92
- self.config_dirs.remove(path)
93
- self.config_dirs.append(path)
105
+
106
+ # last, but not least /etc/${config_dir}
107
+ path = Path("/etc") / self.config_dir
108
+ if path not in self.config_dirs:
109
+ self.config_dirs.append(path)
110
+
111
+ # And now revert the list, so the lowest prioritized dirs come first,
112
+ # and the highest prioritized dir comes at last
113
+ self.config_dirs.reverse()
94
114
 
95
115
  # -------------------------------------------------------------------------
96
116
  def _init_stems(self, append_appname_to_stems, additional_stems=None):
@@ -34,7 +34,7 @@ from ..errors import GenericSocketError
34
34
  from ..handling_obj import HandlingObject
35
35
  from ..xlate import XLATOR
36
36
 
37
- __version__ = "0.8.0"
37
+ __version__ = "0.8.1"
38
38
 
39
39
  LOG = logging.getLogger(__name__)
40
40
 
@@ -689,14 +689,18 @@ class GenericSocket(HandlingObject):
689
689
  def __enter__(self):
690
690
  """Execute this action, when this socket will be opened by the with-block."""
691
691
  LOG.debug(
692
- _("Opened the {cls} {name!r} ...").format(cls=self.__class__.__name__, name=self.name)
692
+ _("Opened the {cls} {name} ...").format(
693
+ cls=self.__class__.__name__, name=self.colored(self.name, "cyan")
694
+ )
693
695
  )
694
696
 
695
697
  # -------------------------------------------------------------------------
696
698
  def __exit__(self, exc_type, exc_val, exc_traceback):
697
699
  """Exit action at the end of the with-block - closing socket."""
698
700
  LOG.debug(
699
- _("Closing the {cls} {name!r} ...").format(cls=self.__class__.__name__, name=self.name)
701
+ _("Closing the {cls} {name} ...").format(
702
+ cls=self.__class__.__name__, name=self.colored(self.name, "cyan")
703
+ )
700
704
  )
701
705
 
702
706
  self.close()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes