python3-cyberfusion-queue-support 1.1.1.1.3__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 (28) hide show
  1. python3-cyberfusion-queue-support-1.1.1.1.3/PKG-INFO +61 -0
  2. python3-cyberfusion-queue-support-1.1.1.1.3/README.md +51 -0
  3. python3-cyberfusion-queue-support-1.1.1.1.3/pyproject.toml +21 -0
  4. python3-cyberfusion-queue-support-1.1.1.1.3/setup.cfg +12 -0
  5. python3-cyberfusion-queue-support-1.1.1.1.3/setup.py +25 -0
  6. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/__init__.py +74 -0
  7. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/exceptions/__init__.py +39 -0
  8. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/interfaces.py +38 -0
  9. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/items/__init__.py +22 -0
  10. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/items/chmod.py +78 -0
  11. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/items/chown.py +144 -0
  12. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/items/command.py +67 -0
  13. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/items/copy.py +68 -0
  14. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/items/mkdir.py +61 -0
  15. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/items/move.py +68 -0
  16. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/items/systemd_tmp_files_create.py +57 -0
  17. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/items/systemd_unit_disable.py +61 -0
  18. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/items/systemd_unit_enable.py +59 -0
  19. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/items/systemd_unit_reload.py +57 -0
  20. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/items/systemd_unit_restart.py +57 -0
  21. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/items/systemd_unit_stop.py +57 -0
  22. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/items/unlink.py +61 -0
  23. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/outcomes.py +311 -0
  24. python3-cyberfusion-queue-support-1.1.1.1.3/src/cyberfusion/QueueSupport/utilities.py +9 -0
  25. python3-cyberfusion-queue-support-1.1.1.1.3/src/python3_cyberfusion_queue_support.egg-info/PKG-INFO +61 -0
  26. python3-cyberfusion-queue-support-1.1.1.1.3/src/python3_cyberfusion_queue_support.egg-info/SOURCES.txt +27 -0
  27. python3-cyberfusion-queue-support-1.1.1.1.3/src/python3_cyberfusion_queue_support.egg-info/dependency_links.txt +1 -0
  28. python3-cyberfusion-queue-support-1.1.1.1.3/src/python3_cyberfusion_queue_support.egg-info/top_level.txt +1 -0
@@ -0,0 +1,61 @@
1
+ Metadata-Version: 2.1
2
+ Name: python3-cyberfusion-queue-support
3
+ Version: 1.1.1.1.3
4
+ Summary: Library to queue actions.
5
+ Home-page: https://github.com/CyberfusionIO/python3-cyberfusion-queue-support
6
+ Author: Cyberfusion
7
+ Author-email: support@cyberfusion.io
8
+ Platform: linux
9
+ Description-Content-Type: text/markdown
10
+
11
+ # python3-cyberfusion-queue-support
12
+
13
+ Library to queue actions.
14
+
15
+ # Install
16
+
17
+ ## PyPI
18
+
19
+ Run the following command to install the package from PyPI:
20
+
21
+ pip3 install python3-cyberfusion-queue-support
22
+
23
+ ## Generic
24
+
25
+ Run the following command to create a source distribution:
26
+
27
+ python3 setup.py sdist
28
+
29
+ ## Debian
30
+
31
+ Run the following commands to build a Debian package:
32
+
33
+ mk-build-deps -i -t 'apt -o Debug::pkgProblemResolver=yes --no-install-recommends -y'
34
+ dpkg-buildpackage -us -uc
35
+
36
+ # Configure
37
+
38
+ No configuration is supported.
39
+
40
+ # Usage
41
+
42
+ ## Example
43
+
44
+ ```python
45
+ from cyberfusion.QueueSupport import Queue
46
+ from cyberfusion.QueueSupport.items.chmod import ChmodItem
47
+
48
+ queue = Queue()
49
+
50
+ item = ChmodItem(path="/tmp/example.txt", mode=0o600)
51
+ print(item.outcomes)
52
+
53
+ queue.add(item)
54
+
55
+ preview = True or False
56
+
57
+ outcomes = queue.process(preview=preview)
58
+
59
+ for outcome in outcomes:
60
+ print(str(outcome))
61
+ ```
@@ -0,0 +1,51 @@
1
+ # python3-cyberfusion-queue-support
2
+
3
+ Library to queue actions.
4
+
5
+ # Install
6
+
7
+ ## PyPI
8
+
9
+ Run the following command to install the package from PyPI:
10
+
11
+ pip3 install python3-cyberfusion-queue-support
12
+
13
+ ## Generic
14
+
15
+ Run the following command to create a source distribution:
16
+
17
+ python3 setup.py sdist
18
+
19
+ ## Debian
20
+
21
+ Run the following commands to build a Debian package:
22
+
23
+ mk-build-deps -i -t 'apt -o Debug::pkgProblemResolver=yes --no-install-recommends -y'
24
+ dpkg-buildpackage -us -uc
25
+
26
+ # Configure
27
+
28
+ No configuration is supported.
29
+
30
+ # Usage
31
+
32
+ ## Example
33
+
34
+ ```python
35
+ from cyberfusion.QueueSupport import Queue
36
+ from cyberfusion.QueueSupport.items.chmod import ChmodItem
37
+
38
+ queue = Queue()
39
+
40
+ item = ChmodItem(path="/tmp/example.txt", mode=0o600)
41
+ print(item.outcomes)
42
+
43
+ queue.add(item)
44
+
45
+ preview = True or False
46
+
47
+ outcomes = queue.process(preview=preview)
48
+
49
+ for outcome in outcomes:
50
+ print(str(outcome))
51
+ ```
@@ -0,0 +1,21 @@
1
+ [tool.isort]
2
+ profile = "black"
3
+ line_length = 79
4
+ known_first_party = ["cyberfusion"]
5
+ default_section = "THIRDPARTY"
6
+
7
+ [tool.black]
8
+ line-length = 79
9
+ exclude = '''
10
+ (
11
+ /(
12
+ \.eggs # exclude a few common directories in the
13
+ | \.git # root of the project
14
+ | \.hg
15
+ | \.mypy_cache
16
+ | \.tox
17
+ | \.venv
18
+ | venv
19
+ )/
20
+ )
21
+ '''
@@ -0,0 +1,12 @@
1
+ [aliases]
2
+ test = pytest
3
+
4
+ [tool:pytest]
5
+ norecursedirs = .git build dist *.egg __pycache__ .cache
6
+ testpaths = tests
7
+ junit_suite_name = python3-cyberfusion-queue-support
8
+
9
+ [egg_info]
10
+ tag_build =
11
+ tag_date = 0
12
+
@@ -0,0 +1,25 @@
1
+ """A setuptools based setup module."""
2
+
3
+ from setuptools import setup
4
+
5
+ with open("README.md", "r", encoding="utf-8") as fh:
6
+ long_description = fh.read()
7
+
8
+ setup(
9
+ name="python3-cyberfusion-queue-support",
10
+ version="1.1.1.1.3",
11
+ description="Library to queue actions.",
12
+ long_description=long_description,
13
+ long_description_content_type="text/markdown",
14
+ author="Cyberfusion",
15
+ author_email="support@cyberfusion.io",
16
+ url="https://github.com/CyberfusionIO/python3-cyberfusion-queue-support",
17
+ platforms=["linux"],
18
+ packages=[
19
+ "cyberfusion.QueueSupport",
20
+ "cyberfusion.QueueSupport.items",
21
+ "cyberfusion.QueueSupport.exceptions",
22
+ ],
23
+ package_dir={"": "src"},
24
+ data_files=[],
25
+ )
@@ -0,0 +1,74 @@
1
+ """Classes for queue."""
2
+
3
+ import logging
4
+ from typing import List
5
+
6
+ from cyberfusion.QueueSupport.exceptions import QueueFulfillFailed
7
+ from cyberfusion.QueueSupport.interfaces import OutcomeInterface
8
+ from cyberfusion.QueueSupport.items import _Item
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class Queue:
14
+ """Represents queue."""
15
+
16
+ def __init__(self) -> None:
17
+ """Set attributes."""
18
+ self.items: List[_Item] = []
19
+
20
+ def add(self, item: _Item, *, move_duplicate_last: bool = True) -> None:
21
+ """Add item to queue."""
22
+ if item not in self.items:
23
+ self.items.append(item)
24
+
25
+ logger.info(
26
+ "Added item to queue (reference: '%s')", item.reference
27
+ )
28
+ else:
29
+ # If item already in queue, move to last place
30
+
31
+ if move_duplicate_last:
32
+ self.items.append(self.items.pop(self.items.index(item)))
33
+
34
+ logger.info(
35
+ "Added item to queue (reference: '%s') (moving duplicate last)",
36
+ item.reference,
37
+ )
38
+ else:
39
+ logger.info(
40
+ "Didn't add item to queue (reference: '%s') (already present)",
41
+ item.reference,
42
+ )
43
+
44
+ def process(self, preview: bool) -> List[OutcomeInterface]:
45
+ """Process items."""
46
+ logger.info("Processing items")
47
+
48
+ results = []
49
+
50
+ for item in self.items:
51
+ logger.info("Processing item '%s'", item.reference)
52
+
53
+ if not item.hide_outcomes:
54
+ results.extend(item.outcomes)
55
+
56
+ if not preview:
57
+ try:
58
+ logger.info("Fulfilling item '%s'", item.reference)
59
+
60
+ item.fulfill()
61
+
62
+ logger.info("Fulfilled item '%s'", item.reference)
63
+ except QueueFulfillFailed:
64
+ raise
65
+ except Exception as e:
66
+ raise QueueFulfillFailed(
67
+ item,
68
+ ) from e
69
+
70
+ logger.info("Processed item '%s'", item.reference)
71
+
72
+ logger.info("Processed items")
73
+
74
+ return results
@@ -0,0 +1,39 @@
1
+ """Exceptions."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import List
5
+
6
+ from cyberfusion.QueueSupport.items import _Item
7
+
8
+
9
+ class ItemError(Exception):
10
+ """Issues with item."""
11
+
12
+ pass
13
+
14
+
15
+ @dataclass
16
+ class PathIsSymlinkError(ItemError):
17
+ """Path is symlink."""
18
+
19
+ path: str
20
+
21
+
22
+ @dataclass
23
+ class QueueFulfillFailed(Exception):
24
+ """Error occurred while fulfilling queue."""
25
+
26
+ item: _Item
27
+
28
+
29
+ @dataclass
30
+ class CommandQueueFulfillFailed(QueueFulfillFailed):
31
+ """Error occurred while fulfilling queue, with command item."""
32
+
33
+ command: List[str]
34
+ stdout: str
35
+ stderr: str
36
+
37
+ def __str__(self) -> str:
38
+ """Get string representation."""
39
+ return f"Command:\n\n{self.command}\n\nStdout:\n\n{self.stdout}\n\nStderr:\n\n{self.stderr}"
@@ -0,0 +1,38 @@
1
+ """Interfaces."""
2
+
3
+ from abc import ABCMeta, abstractmethod
4
+ from typing import List
5
+
6
+
7
+ class OutcomeInterface(metaclass=ABCMeta):
8
+ """Interface for outcomes."""
9
+
10
+ @abstractmethod
11
+ def __str__(self) -> str: # pragma: no cover
12
+ """Get human-readable string."""
13
+ pass
14
+
15
+ @abstractmethod
16
+ def __eq__(self, other: object) -> bool: # pragma: no cover
17
+ """Get equality based on attributes."""
18
+ pass
19
+
20
+
21
+ class ItemInterface(metaclass=ABCMeta):
22
+ """Interface for items."""
23
+
24
+ @property
25
+ @abstractmethod
26
+ def outcomes(self) -> List[OutcomeInterface]: # pragma: no cover
27
+ """Get outcomes of calling self.fulfill."""
28
+ pass
29
+
30
+ @abstractmethod
31
+ def fulfill(self) -> None: # pragma: no cover
32
+ """Fulfill outcomes."""
33
+ pass
34
+
35
+ @abstractmethod
36
+ def __eq__(self, other: object) -> bool: # pragma: no cover
37
+ """Get equality based on attributes."""
38
+ pass
@@ -0,0 +1,22 @@
1
+ """Items."""
2
+
3
+ import logging
4
+ from typing import Optional
5
+
6
+ from cyberfusion.QueueSupport.interfaces import ItemInterface
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ class _Item(ItemInterface):
12
+ """Represents base item."""
13
+
14
+ @property
15
+ def hide_outcomes(self) -> bool:
16
+ """Get if outcomes should be hidden."""
17
+ return self._hide_outcomes
18
+
19
+ @property
20
+ def reference(self) -> Optional[str]:
21
+ """Get free-form reference, for users' own administrations."""
22
+ return self._reference
@@ -0,0 +1,78 @@
1
+ """Item."""
2
+
3
+ import logging
4
+ import os
5
+ from typing import List, Optional
6
+
7
+ from cyberfusion.QueueSupport.exceptions import PathIsSymlinkError
8
+ from cyberfusion.QueueSupport.interfaces import OutcomeInterface
9
+ from cyberfusion.QueueSupport.items import _Item
10
+ from cyberfusion.QueueSupport.outcomes import ChmodItemModeChangeOutcome
11
+ from cyberfusion.QueueSupport.utilities import get_decimal_permissions
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class ChmodItem(_Item):
17
+ """Represents item."""
18
+
19
+ def __init__(
20
+ self,
21
+ *,
22
+ path: str,
23
+ mode: int,
24
+ reference: Optional[str] = None,
25
+ hide_outcomes: bool = False,
26
+ ) -> None:
27
+ """Set attributes."""
28
+ self.path = path
29
+ self.mode = mode
30
+ self._reference = reference
31
+ self._hide_outcomes = hide_outcomes
32
+
33
+ if os.path.islink(self.path):
34
+ raise PathIsSymlinkError(self.path)
35
+
36
+ @property
37
+ def outcomes(self) -> List[OutcomeInterface]:
38
+ """Get outcomes of calling self.fulfill."""
39
+ outcomes = []
40
+
41
+ if not os.path.exists(self.path):
42
+ outcomes.append(
43
+ ChmodItemModeChangeOutcome(
44
+ path=self.path, old_mode=None, new_mode=self.mode
45
+ )
46
+ )
47
+ else:
48
+ old_mode = get_decimal_permissions(self.path)
49
+ mode_changed = old_mode != self.mode
50
+
51
+ if mode_changed:
52
+ outcomes.append(
53
+ ChmodItemModeChangeOutcome(
54
+ path=self.path, old_mode=old_mode, new_mode=self.mode
55
+ )
56
+ )
57
+
58
+ return outcomes
59
+
60
+ def fulfill(self) -> None:
61
+ """Fulfill outcomes."""
62
+ mode_change_outcomes = [
63
+ x
64
+ for x in self.outcomes
65
+ if isinstance(x, ChmodItemModeChangeOutcome)
66
+ ]
67
+
68
+ if mode_change_outcomes:
69
+ os.chmod(
70
+ mode_change_outcomes[0].path, mode_change_outcomes[0].new_mode
71
+ )
72
+
73
+ def __eq__(self, other: object) -> bool:
74
+ """Get equality based on attributes."""
75
+ if not isinstance(other, ChmodItem):
76
+ return False
77
+
78
+ return other.path == self.path and other.mode == self.mode
@@ -0,0 +1,144 @@
1
+ """Item."""
2
+
3
+ import grp
4
+ import logging
5
+ import os
6
+ import pwd
7
+ from grp import getgrgid
8
+ from pwd import getpwuid
9
+ from typing import List, Optional
10
+
11
+ from cyberfusion.QueueSupport.exceptions import PathIsSymlinkError
12
+ from cyberfusion.QueueSupport.interfaces import OutcomeInterface
13
+ from cyberfusion.QueueSupport.items import _Item
14
+ from cyberfusion.QueueSupport.outcomes import (
15
+ ChownItemGroupChangeOutcome,
16
+ ChownItemOwnerChangeOutcome,
17
+ )
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ def get_uid(username: str) -> int:
23
+ """Get UID by username."""
24
+ return pwd.getpwnam(username).pw_uid
25
+
26
+
27
+ def get_gid(group_name: str) -> int:
28
+ """Get GID by group name."""
29
+ return grp.getgrnam(group_name).gr_gid
30
+
31
+
32
+ class ChownItem(_Item):
33
+ """Represents item."""
34
+
35
+ def __init__(
36
+ self,
37
+ *,
38
+ path: str,
39
+ owner_name: str,
40
+ group_name: str,
41
+ reference: Optional[str] = None,
42
+ hide_outcomes: bool = False,
43
+ ) -> None:
44
+ """Set attributes."""
45
+ self.path = path
46
+ self.owner_name = owner_name
47
+ self.group_name = group_name
48
+ self._reference = reference
49
+ self._hide_outcomes = hide_outcomes
50
+
51
+ if os.path.islink(self.path):
52
+ raise PathIsSymlinkError(self.path)
53
+
54
+ @property
55
+ def outcomes(self) -> List[OutcomeInterface]:
56
+ """Get outcomes of calling self.fulfill."""
57
+ outcomes = []
58
+
59
+ if not os.path.exists(self.path):
60
+ outcomes.extend(
61
+ [
62
+ ChownItemOwnerChangeOutcome(
63
+ path=self.path,
64
+ old_owner_name=None,
65
+ new_owner_name=self.owner_name,
66
+ ),
67
+ ChownItemGroupChangeOutcome(
68
+ path=self.path,
69
+ old_group_name=None,
70
+ new_group_name=self.group_name,
71
+ ),
72
+ ]
73
+ )
74
+ else:
75
+ try:
76
+ old_owner_name = getpwuid(os.stat(self.path).st_uid).pw_name
77
+ except KeyError:
78
+ old_owner_name = "(no user with UID exists)"
79
+
80
+ try:
81
+ old_group_name = getgrgid(os.stat(self.path).st_gid).gr_name
82
+ except KeyError:
83
+ old_group_name = "(no group with GID exists)"
84
+
85
+ owner_name_changed = old_owner_name != self.owner_name
86
+ group_name_changed = old_group_name != self.group_name
87
+
88
+ if owner_name_changed:
89
+ outcomes.append(
90
+ ChownItemOwnerChangeOutcome(
91
+ path=self.path,
92
+ old_owner_name=old_owner_name,
93
+ new_owner_name=self.owner_name,
94
+ )
95
+ )
96
+
97
+ if group_name_changed:
98
+ outcomes.append(
99
+ ChownItemGroupChangeOutcome(
100
+ path=self.path,
101
+ old_group_name=old_group_name,
102
+ new_group_name=self.group_name,
103
+ )
104
+ )
105
+
106
+ return outcomes
107
+
108
+ def fulfill(self) -> None:
109
+ """Fulfill outcomes."""
110
+ owner_name_change_outcomes = [
111
+ x
112
+ for x in self.outcomes
113
+ if isinstance(x, ChownItemOwnerChangeOutcome)
114
+ ]
115
+ group_name_change_outcomes = [
116
+ x
117
+ for x in self.outcomes
118
+ if isinstance(x, ChownItemGroupChangeOutcome)
119
+ ]
120
+
121
+ if owner_name_change_outcomes:
122
+ os.chown(
123
+ owner_name_change_outcomes[0].path,
124
+ uid=get_uid(owner_name_change_outcomes[0].new_owner_name),
125
+ gid=-1,
126
+ )
127
+
128
+ if group_name_change_outcomes:
129
+ os.chown(
130
+ group_name_change_outcomes[0].path,
131
+ uid=-1,
132
+ gid=get_gid(group_name_change_outcomes[0].new_group_name),
133
+ )
134
+
135
+ def __eq__(self, other: object) -> bool:
136
+ """Get equality based on attributes."""
137
+ if not isinstance(other, ChownItem):
138
+ return False
139
+
140
+ return (
141
+ other.path == self.path
142
+ and other.owner_name == self.owner_name
143
+ and other.group_name == self.group_name
144
+ )
@@ -0,0 +1,67 @@
1
+ """Item."""
2
+
3
+ import logging
4
+ import subprocess
5
+ from typing import List, Optional
6
+
7
+ from cyberfusion.QueueSupport.exceptions import CommandQueueFulfillFailed
8
+ from cyberfusion.QueueSupport.interfaces import OutcomeInterface
9
+ from cyberfusion.QueueSupport.items import _Item
10
+ from cyberfusion.QueueSupport.outcomes import CommandItemRunOutcome
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class CommandItem(_Item):
16
+ """Represents item."""
17
+
18
+ def __init__(
19
+ self,
20
+ *,
21
+ command: List[str],
22
+ reference: Optional[str] = None,
23
+ hide_outcomes: bool = False,
24
+ ) -> None:
25
+ """Set attributes."""
26
+ self.command = command
27
+ self._reference = reference
28
+ self._hide_outcomes = hide_outcomes
29
+
30
+ @property
31
+ def outcomes(self) -> List[OutcomeInterface]:
32
+ """Get outcomes of calling self.fulfill."""
33
+ outcomes = []
34
+
35
+ outcomes.append(CommandItemRunOutcome(command=self.command))
36
+
37
+ return outcomes
38
+
39
+ def fulfill(self) -> None:
40
+ """Fulfill outcomes."""
41
+ run_outcomes = [
42
+ x for x in self.outcomes if isinstance(x, CommandItemRunOutcome)
43
+ ]
44
+
45
+ command = run_outcomes[0].command
46
+
47
+ try:
48
+ output = subprocess.run(
49
+ command,
50
+ check=True,
51
+ text=True,
52
+ capture_output=True,
53
+ )
54
+
55
+ logger.info("Command stdout: %s", output.stdout)
56
+ logger.info("Command stderr: %s", output.stderr)
57
+ except subprocess.CalledProcessError as e:
58
+ raise CommandQueueFulfillFailed(
59
+ self, command=command, stdout=e.stdout, stderr=e.stderr
60
+ ) from e
61
+
62
+ def __eq__(self, other: object) -> bool:
63
+ """Get equality based on attributes."""
64
+ if not isinstance(other, CommandItem):
65
+ return False
66
+
67
+ return other.command == self.command