python3-cyberfusion-queue-support 1.6__tar.gz → 2.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 (33) hide show
  1. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/PKG-INFO +3 -1
  2. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/pyproject.toml +3 -1
  3. python3_cyberfusion_queue_support-2.0/src/cyberfusion/QueueSupport/__init__.py +150 -0
  4. python3_cyberfusion_queue_support-2.0/src/cyberfusion/QueueSupport/database.py +106 -0
  5. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/interfaces.py +1 -1
  6. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/__init__.py +13 -1
  7. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/chmod.py +6 -2
  8. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/chown.py +8 -2
  9. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/command.py +6 -2
  10. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/copy.py +28 -10
  11. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/mkdir.py +6 -2
  12. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/move.py +6 -2
  13. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/rmtree.py +6 -2
  14. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/systemd_daemon_reload.py +6 -2
  15. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/systemd_tmp_files_create.py +6 -2
  16. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/systemd_unit_disable.py +6 -2
  17. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/systemd_unit_enable.py +6 -2
  18. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/systemd_unit_reload.py +6 -2
  19. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/systemd_unit_restart.py +6 -2
  20. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/systemd_unit_start.py +6 -2
  21. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/systemd_unit_stop.py +6 -2
  22. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/items/unlink.py +6 -2
  23. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/outcomes.py +6 -3
  24. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/python3_cyberfusion_queue_support.egg-info/PKG-INFO +3 -1
  25. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/python3_cyberfusion_queue_support.egg-info/SOURCES.txt +1 -0
  26. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/python3_cyberfusion_queue_support.egg-info/requires.txt +2 -0
  27. python3_cyberfusion_queue_support-1.6/src/cyberfusion/QueueSupport/__init__.py +0 -72
  28. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/README.md +0 -0
  29. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/setup.cfg +0 -0
  30. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/exceptions/__init__.py +0 -0
  31. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/cyberfusion/QueueSupport/utilities.py +0 -0
  32. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/python3_cyberfusion_queue_support.egg-info/dependency_links.txt +0 -0
  33. {python3_cyberfusion_queue_support-1.6 → python3_cyberfusion_queue_support-2.0}/src/python3_cyberfusion_queue_support.egg-info/top_level.txt +0 -0
@@ -1,11 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python3-cyberfusion-queue-support
3
- Version: 1.6
3
+ Version: 2.0
4
4
  Summary: Library to queue actions.
5
5
  Author-email: Cyberfusion <support@cyberfusion.io>
6
6
  Project-URL: Source, https://github.com/CyberfusionIO/python3-cyberfusion-queue-support
7
7
  Description-Content-Type: text/markdown
8
8
  Requires-Dist: python3-cyberfusion-systemd-support~=2.1
9
+ Requires-Dist: alembic==1.8.1
10
+ Requires-Dist: SQLAlchemy==1.4.46
9
11
 
10
12
  # python3-cyberfusion-queue-support
11
13
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python3-cyberfusion-queue-support"
7
- version = "1.6"
7
+ version = "2.0"
8
8
  description = "Library to queue actions."
9
9
  readme = "README.md"
10
10
  authors = [
@@ -12,6 +12,8 @@ authors = [
12
12
  ]
13
13
  dependencies = [
14
14
  "python3-cyberfusion-systemd-support~=2.1",
15
+ "alembic==1.8.1",
16
+ "SQLAlchemy==1.4.46",
15
17
  ]
16
18
 
17
19
  [project.urls]
@@ -0,0 +1,150 @@
1
+ """Classes for queue."""
2
+
3
+ import logging
4
+ from copy import copy
5
+ from dataclasses import dataclass
6
+ from typing import List
7
+
8
+ from cyberfusion.QueueSupport.database import (
9
+ Queue as QueueModel,
10
+ QueueItem,
11
+ make_database_session,
12
+ QueueItemOutcome,
13
+ QueueProcess,
14
+ )
15
+ from cyberfusion.QueueSupport.exceptions import QueueFulfillFailed
16
+ from cyberfusion.QueueSupport.interfaces import OutcomeInterface
17
+ from cyberfusion.QueueSupport.items import _Item
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ @dataclass
23
+ class QueueItemMapping:
24
+ """Queue item mapping."""
25
+
26
+ item: _Item
27
+ database_object: QueueItem
28
+
29
+
30
+ class Queue:
31
+ """Represents queue."""
32
+
33
+ def __init__(self) -> None:
34
+ """Set attributes."""
35
+ self.item_mappings: List[QueueItemMapping] = []
36
+
37
+ self._database_session = make_database_session()
38
+
39
+ object_ = QueueModel()
40
+
41
+ self._database_session.add(object_)
42
+ self._database_session.commit()
43
+
44
+ self.queue_database_object = object_
45
+
46
+ def add(self, item: _Item, *, run_duplicate_last: bool = True) -> None:
47
+ """Add item to queue."""
48
+ deduplicated = False
49
+
50
+ existing_item_index = next(
51
+ (
52
+ index
53
+ for index, item_mapping in enumerate(self.item_mappings)
54
+ if item_mapping.item == item
55
+ ),
56
+ None,
57
+ )
58
+
59
+ if existing_item_index is not None:
60
+ if run_duplicate_last:
61
+ self.item_mappings[
62
+ existing_item_index
63
+ ].database_object.deduplicated = True
64
+
65
+ self._database_session.commit()
66
+ else:
67
+ deduplicated = True
68
+
69
+ item_dict = copy(item.__dict__)
70
+
71
+ del item_dict["_reference"]
72
+ del item_dict["_hide_outcomes"]
73
+
74
+ object_ = QueueItem(
75
+ queue=self.queue_database_object,
76
+ type=item.__class__.__name__,
77
+ reference=item.reference,
78
+ hide_outcomes=item.hide_outcomes,
79
+ deduplicated=deduplicated,
80
+ attributes=item_dict,
81
+ )
82
+
83
+ self._database_session.add(object_)
84
+ self._database_session.commit()
85
+
86
+ self.item_mappings.append(QueueItemMapping(item, object_))
87
+
88
+ def process(self, preview: bool) -> List[OutcomeInterface]:
89
+ """Process items."""
90
+ logger.debug("Processing items")
91
+
92
+ process_object = QueueProcess(
93
+ queue_id=self.queue_database_object.id,
94
+ preview=preview,
95
+ )
96
+
97
+ self._database_session.add(process_object)
98
+ self._database_session.commit()
99
+
100
+ outcomes = []
101
+
102
+ for item_mapping in [
103
+ item_mapping
104
+ for item_mapping in self.item_mappings
105
+ if not item_mapping.database_object.deduplicated
106
+ ]:
107
+ logger.debug(
108
+ "Processing item with id '%s'", item_mapping.database_object.id
109
+ )
110
+
111
+ if preview:
112
+ if not item_mapping.item.hide_outcomes:
113
+ outcomes.extend(item_mapping.item.outcomes)
114
+ else:
115
+ try:
116
+ logger.debug(
117
+ "Fulfilling item with id '%s'", item_mapping.database_object.id
118
+ )
119
+
120
+ fulfill_outcomes = item_mapping.item.fulfill()
121
+
122
+ if not item_mapping.item.hide_outcomes:
123
+ outcomes.extend(fulfill_outcomes)
124
+
125
+ logger.debug(
126
+ "Fulfilled item with id '%s'", item_mapping.database_object.id
127
+ )
128
+ except QueueFulfillFailed:
129
+ raise
130
+ except Exception as e:
131
+ raise QueueFulfillFailed(
132
+ item_mapping.item,
133
+ ) from e
134
+
135
+ for outcome in outcomes:
136
+ outcome_object = QueueItemOutcome(
137
+ queue_item=item_mapping.database_object,
138
+ queue_process=process_object,
139
+ type=outcome.__class__.__name__,
140
+ attributes=outcome.__dict__,
141
+ )
142
+
143
+ self._database_session.add(outcome_object)
144
+ self._database_session.commit()
145
+
146
+ logger.debug("Processed item with id '%s'", item_mapping.database_object.id)
147
+
148
+ logger.debug("Processed items")
149
+
150
+ return outcomes
@@ -0,0 +1,106 @@
1
+ import os
2
+ import sqlite3
3
+ from datetime import datetime, timezone
4
+ from sqlalchemy.pool.base import _ConnectionRecord
5
+ from sqlalchemy import ForeignKey, MetaData, Boolean
6
+ from sqlalchemy import create_engine, Column, DateTime, Integer, String
7
+ from sqlalchemy.orm import Session, sessionmaker, relationship
8
+ from sqlalchemy.ext.declarative import declarative_base
9
+ from sqlalchemy.engine import Engine
10
+ from sqlalchemy import event
11
+ from sqlalchemy.types import JSON
12
+
13
+
14
+ @event.listens_for(Engine, "connect") # type: ignore[misc]
15
+ def set_sqlite_pragma(
16
+ dbapi_connection: sqlite3.Connection, connection_record: _ConnectionRecord
17
+ ) -> None:
18
+ """Enable foreign key support.
19
+
20
+ This is needed for cascade deletes to work.
21
+
22
+ See https://docs.sqlalchemy.org/en/13/dialects/sqlite.html#sqlite-foreign-keys
23
+ """
24
+ cursor = dbapi_connection.cursor()
25
+
26
+ cursor.execute("PRAGMA foreign_keys=ON")
27
+
28
+ cursor.close()
29
+
30
+
31
+ def get_database_path() -> str: # pragma: no cover
32
+ """Get database path."""
33
+ return os.path.join(os.path.sep, "var", "lib", "queue-support.db")
34
+
35
+
36
+ def make_database_session() -> Session:
37
+ engine = create_engine(
38
+ "sqlite:///" + get_database_path(), connect_args={"check_same_thread": False}
39
+ )
40
+
41
+ return sessionmaker(bind=engine)()
42
+
43
+
44
+ naming_convention = {
45
+ "ix": "ix_%(column_0_label)s",
46
+ "uq": "uq_%(table_name)s_%(column_0_name)s",
47
+ "ck": "ck_%(table_name)s_%(constraint_name)s",
48
+ "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
49
+ "pk": "pk_%(table_name)s",
50
+ }
51
+
52
+ metadata = MetaData(naming_convention=naming_convention)
53
+
54
+ Base = declarative_base(metadata=metadata)
55
+
56
+
57
+ class BaseModel(Base): # type: ignore[misc, valid-type]
58
+ """Base model."""
59
+
60
+ __abstract__ = True
61
+
62
+ id = Column(Integer, primary_key=True)
63
+ created_at = Column(DateTime, default=datetime.now(timezone.utc), nullable=False)
64
+
65
+
66
+ class Queue(BaseModel):
67
+ """Queue model."""
68
+
69
+ __tablename__ = "queues"
70
+
71
+
72
+ class QueueProcess(BaseModel):
73
+ """QueueProcess model."""
74
+
75
+ __tablename__ = "queue_processes"
76
+
77
+ queue_id = Column(Integer, ForeignKey("queues.id"), nullable=False)
78
+ queue = relationship("Queue")
79
+ preview = Column(Boolean, nullable=False)
80
+
81
+
82
+ class QueueItem(BaseModel):
83
+ """QueueItem model."""
84
+
85
+ __tablename__ = "queue_items"
86
+
87
+ queue_id = Column(Integer, ForeignKey("queues.id"), nullable=False)
88
+ queue = relationship("Queue")
89
+ type = Column(String(length=255), nullable=False)
90
+ reference = Column(String(length=255), nullable=True)
91
+ hide_outcomes = Column(Boolean, nullable=False)
92
+ deduplicated = Column(Boolean, nullable=False)
93
+ attributes = Column(JSON, nullable=False)
94
+
95
+
96
+ class QueueItemOutcome(BaseModel):
97
+ """QueueItemOutcome model."""
98
+
99
+ __tablename__ = "queue_item_outcomes"
100
+
101
+ queue_item_id = Column(Integer, ForeignKey("queue_items.id"), nullable=False)
102
+ queue_item = relationship("QueueItem")
103
+ queue_process_id = Column(Integer, ForeignKey("queue_processes.id"), nullable=False)
104
+ queue_process = relationship("QueueProcess")
105
+ type = Column(String(length=255), nullable=False)
106
+ attributes = Column(JSON, nullable=False)
@@ -28,7 +28,7 @@ class ItemInterface(metaclass=ABCMeta):
28
28
  pass
29
29
 
30
30
  @abstractmethod
31
- def fulfill(self) -> None: # pragma: no cover
31
+ def fulfill(self) -> List[OutcomeInterface]: # pragma: no cover
32
32
  """Fulfill outcomes."""
33
33
  pass
34
34
 
@@ -1,6 +1,7 @@
1
1
  """Items."""
2
2
 
3
3
  import logging
4
+ from abc import ABC, abstractmethod
4
5
  from typing import Optional
5
6
 
6
7
  from cyberfusion.QueueSupport.interfaces import ItemInterface
@@ -8,9 +9,20 @@ from cyberfusion.QueueSupport.interfaces import ItemInterface
8
9
  logger = logging.getLogger(__name__)
9
10
 
10
11
 
11
- class _Item(ItemInterface):
12
+ class _Item(ItemInterface, ABC):
12
13
  """Represents base item."""
13
14
 
15
+ @abstractmethod
16
+ def __init__(
17
+ self,
18
+ *,
19
+ reference: Optional[str] = None,
20
+ hide_outcomes: bool = False,
21
+ ) -> None: # pragma: no cover
22
+ """Set attributes."""
23
+ self._reference = reference
24
+ self._hide_outcomes = hide_outcomes
25
+
14
26
  @property
15
27
  def hide_outcomes(self) -> bool:
16
28
  """Get if outcomes should be hidden."""
@@ -56,11 +56,15 @@ class ChmodItem(_Item):
56
56
 
57
57
  return outcomes
58
58
 
59
- def fulfill(self) -> None:
59
+ def fulfill(self) -> List[ChmodItemModeChangeOutcome]:
60
60
  """Fulfill outcomes."""
61
- for outcome in self.outcomes:
61
+ outcomes = self.outcomes
62
+
63
+ for outcome in outcomes:
62
64
  os.chmod(outcome.path, outcome.new_mode)
63
65
 
66
+ return outcomes
67
+
64
68
  def __eq__(self, other: object) -> bool:
65
69
  """Get equality based on attributes."""
66
70
  if not isinstance(other, ChmodItem):
@@ -106,9 +106,13 @@ class ChownItem(_Item):
106
106
 
107
107
  return outcomes
108
108
 
109
- def fulfill(self) -> None:
109
+ def fulfill(
110
+ self,
111
+ ) -> List[ChownItemOwnerChangeOutcome | ChownItemGroupChangeOutcome]:
110
112
  """Fulfill outcomes."""
111
- for outcome in self.outcomes:
113
+ outcomes = self.outcomes
114
+
115
+ for outcome in outcomes:
112
116
  if isinstance(outcome, ChownItemOwnerChangeOutcome):
113
117
  os.chown(
114
118
  outcome.path,
@@ -122,6 +126,8 @@ class ChownItem(_Item):
122
126
  gid=get_gid(outcome.new_group_name),
123
127
  )
124
128
 
129
+ return outcomes
130
+
125
131
  def __eq__(self, other: object) -> bool:
126
132
  """Get equality based on attributes."""
127
133
  if not isinstance(other, ChownItem):
@@ -35,9 +35,11 @@ class CommandItem(_Item):
35
35
 
36
36
  return outcomes
37
37
 
38
- def fulfill(self) -> None:
38
+ def fulfill(self) -> List[CommandItemRunOutcome]:
39
39
  """Fulfill outcomes."""
40
- for outcome in self.outcomes:
40
+ outcomes = self.outcomes
41
+
42
+ for outcome in outcomes:
41
43
  try:
42
44
  output = subprocess.run(
43
45
  outcome.command,
@@ -53,6 +55,8 @@ class CommandItem(_Item):
53
55
  self, command=outcome.command, stdout=e.stdout, stderr=e.stderr
54
56
  ) from e
55
57
 
58
+ return outcomes
59
+
56
60
  def __eq__(self, other: object) -> bool:
57
61
  """Get equality based on attributes."""
58
62
  if not isinstance(other, CommandItem):
@@ -36,22 +36,29 @@ class CopyItem(_Item):
36
36
  if os.path.islink(self.destination):
37
37
  raise PathIsSymlinkError(self.destination)
38
38
 
39
- def _get_changed_lines(self) -> List[str]:
39
+ def _get_changed_lines(self) -> Optional[List[str]]:
40
40
  """Get differences with destination file.
41
41
 
42
- No differences are returned when contents is not string.
42
+ Returns None if the changed_lines could not be determined, for example
43
+ if the destination file is encrypted.
43
44
  """
44
45
  changed_lines = []
45
46
 
46
- contents = []
47
+ destination_contents = []
47
48
 
48
- if os.path.isfile(self.destination):
49
- contents = open(self.destination).readlines()
49
+ try:
50
+ source_contents = open(self.source).readlines()
51
+ except UnicodeDecodeError:
52
+ return None
50
53
 
51
- source_contents = open(self.source).readlines()
54
+ if os.path.isfile(self.destination):
55
+ try:
56
+ destination_contents = open(self.destination).readlines()
57
+ except UnicodeDecodeError:
58
+ return None
52
59
 
53
60
  for line in difflib.unified_diff(
54
- contents,
61
+ destination_contents,
55
62
  source_contents,
56
63
  fromfile=self.source,
57
64
  tofile=self.destination,
@@ -69,7 +76,14 @@ class CopyItem(_Item):
69
76
 
70
77
  changed_lines = self._get_changed_lines()
71
78
 
72
- if not os.path.exists(self.destination) or changed_lines:
79
+ if not os.path.exists(self.destination):
80
+ copy = True
81
+ elif changed_lines is None:
82
+ copy = True
83
+ else:
84
+ copy = bool(changed_lines)
85
+
86
+ if copy:
73
87
  outcomes.append(
74
88
  CopyItemCopyOutcome(
75
89
  source=self.source,
@@ -80,11 +94,15 @@ class CopyItem(_Item):
80
94
 
81
95
  return outcomes
82
96
 
83
- def fulfill(self) -> None:
97
+ def fulfill(self) -> List[CopyItemCopyOutcome]:
84
98
  """Fulfill outcomes."""
85
- for outcome in self.outcomes:
99
+ outcomes = self.outcomes
100
+
101
+ for outcome in outcomes:
86
102
  shutil.copyfile(outcome.source, outcome.destination)
87
103
 
104
+ return outcomes
105
+
88
106
  def __eq__(self, other: object) -> bool:
89
107
  """Get equality based on attributes."""
90
108
  if not isinstance(other, CopyItem):
@@ -43,11 +43,15 @@ class MkdirItem(_Item):
43
43
 
44
44
  return outcomes
45
45
 
46
- def fulfill(self) -> None:
46
+ def fulfill(self) -> List[MkdirItemCreateOutcome]:
47
47
  """Fulfill outcomes."""
48
- for outcome in self.outcomes:
48
+ outcomes = self.outcomes
49
+
50
+ for outcome in outcomes:
49
51
  os.mkdir(outcome.path)
50
52
 
53
+ return outcomes
54
+
51
55
  def __eq__(self, other: object) -> bool:
52
56
  """Get equality based on attributes."""
53
57
  if not isinstance(other, MkdirItem):
@@ -46,11 +46,15 @@ class MoveItem(_Item):
46
46
 
47
47
  return outcomes
48
48
 
49
- def fulfill(self) -> None:
49
+ def fulfill(self) -> List[MoveItemMoveOutcome]:
50
50
  """Fulfill outcomes."""
51
- for outcome in self.outcomes:
51
+ outcomes = self.outcomes
52
+
53
+ for outcome in outcomes:
52
54
  shutil.move(outcome.source, outcome.destination)
53
55
 
56
+ return outcomes
57
+
54
58
  def __eq__(self, other: object) -> bool:
55
59
  """Get equality based on attributes."""
56
60
  if not isinstance(other, MoveItem):
@@ -44,11 +44,15 @@ class RmTreeItem(_Item):
44
44
 
45
45
  return outcomes
46
46
 
47
- def fulfill(self) -> None:
47
+ def fulfill(self) -> List[RmTreeItemRemoveOutcome]:
48
48
  """Fulfill outcomes."""
49
- for outcome in self.outcomes:
49
+ outcomes = self.outcomes
50
+
51
+ for outcome in outcomes:
50
52
  shutil.rmtree(outcome.path)
51
53
 
54
+ return outcomes
55
+
52
56
  def __eq__(self, other: object) -> bool:
53
57
  """Get equality based on attributes."""
54
58
  if not isinstance(other, RmTreeItem):
@@ -35,11 +35,15 @@ class SystemdDaemonReloadItem(_Item):
35
35
 
36
36
  return outcomes
37
37
 
38
- def fulfill(self) -> None:
38
+ def fulfill(self) -> List[SystemdDaemonReloadItemReloadOutcome]:
39
39
  """Fulfill outcomes."""
40
- for _ in self.outcomes:
40
+ outcomes = self.outcomes
41
+
42
+ for _ in outcomes:
41
43
  SystemdManager.daemon_reload()
42
44
 
45
+ return outcomes
46
+
43
47
  def __eq__(self, other: object) -> bool:
44
48
  """Get equality based on attributes."""
45
49
  if not isinstance(other, SystemdDaemonReloadItem):
@@ -36,11 +36,15 @@ class SystemdTmpFilesCreateItem(_Item):
36
36
 
37
37
  return outcomes
38
38
 
39
- def fulfill(self) -> None:
39
+ def fulfill(self) -> List[SystemdTmpFilesCreateItemCreateOutcome]:
40
40
  """Fulfill outcomes."""
41
- for outcome in self.outcomes:
41
+ outcomes = self.outcomes
42
+
43
+ for outcome in outcomes:
42
44
  TmpFileConfigurationFile(outcome.path).create()
43
45
 
46
+ return outcomes
47
+
44
48
  def __eq__(self, other: object) -> bool:
45
49
  """Get equality based on attributes."""
46
50
  if not isinstance(other, SystemdTmpFilesCreateItem):
@@ -39,11 +39,15 @@ class SystemdUnitDisableItem(_Item):
39
39
 
40
40
  return outcomes
41
41
 
42
- def fulfill(self) -> None:
42
+ def fulfill(self) -> List[SystemdUnitDisableItemDisableOutcome]:
43
43
  """Fulfill outcomes."""
44
- for outcome in self.outcomes:
44
+ outcomes = self.outcomes
45
+
46
+ for outcome in outcomes:
45
47
  outcome.unit.disable()
46
48
 
49
+ return outcomes
50
+
47
51
  def __eq__(self, other: object) -> bool:
48
52
  """Get equality based on attributes."""
49
53
  if not isinstance(other, SystemdUnitDisableItem):
@@ -39,11 +39,15 @@ class SystemdUnitEnableItem(_Item):
39
39
 
40
40
  return outcomes
41
41
 
42
- def fulfill(self) -> None:
42
+ def fulfill(self) -> List[SystemdUnitEnableItemEnableOutcome]:
43
43
  """Fulfill outcomes."""
44
- for outcome in self.outcomes:
44
+ outcomes = self.outcomes
45
+
46
+ for outcome in outcomes:
45
47
  outcome.unit.enable()
46
48
 
49
+ return outcomes
50
+
47
51
  def __eq__(self, other: object) -> bool:
48
52
  """Get equality based on attributes."""
49
53
  if not isinstance(other, SystemdUnitEnableItem):
@@ -38,11 +38,15 @@ class SystemdUnitReloadItem(_Item):
38
38
 
39
39
  return outcomes
40
40
 
41
- def fulfill(self) -> None:
41
+ def fulfill(self) -> List[SystemdUnitReloadItemReloadOutcome]:
42
42
  """Fulfill outcomes."""
43
- for outcome in self.outcomes:
43
+ outcomes = self.outcomes
44
+
45
+ for outcome in outcomes:
44
46
  outcome.unit.reload()
45
47
 
48
+ return outcomes
49
+
46
50
  def __eq__(self, other: object) -> bool:
47
51
  """Get equality based on attributes."""
48
52
  if not isinstance(other, SystemdUnitReloadItem):
@@ -38,11 +38,15 @@ class SystemdUnitRestartItem(_Item):
38
38
 
39
39
  return outcomes
40
40
 
41
- def fulfill(self) -> None:
41
+ def fulfill(self) -> List[SystemdUnitRestartItemRestartOutcome]:
42
42
  """Fulfill outcomes."""
43
- for outcome in self.outcomes:
43
+ outcomes = self.outcomes
44
+
45
+ for outcome in outcomes:
44
46
  outcome.unit.restart()
45
47
 
48
+ return outcomes
49
+
46
50
  def __eq__(self, other: object) -> bool:
47
51
  """Get equality based on attributes."""
48
52
  if not isinstance(other, SystemdUnitRestartItem):
@@ -39,11 +39,15 @@ class SystemdUnitStartItem(_Item):
39
39
 
40
40
  return outcomes
41
41
 
42
- def fulfill(self) -> None:
42
+ def fulfill(self) -> List[SystemdUnitStartItemStartOutcome]:
43
43
  """Fulfill outcomes."""
44
- for outcome in self.outcomes:
44
+ outcomes = self.outcomes
45
+
46
+ for outcome in outcomes:
45
47
  outcome.unit.start()
46
48
 
49
+ return outcomes
50
+
47
51
  def __eq__(self, other: object) -> bool:
48
52
  """Get equality based on attributes."""
49
53
  if not isinstance(other, SystemdUnitStartItem):
@@ -37,11 +37,15 @@ class SystemdUnitStopItem(_Item):
37
37
 
38
38
  return outcomes
39
39
 
40
- def fulfill(self) -> None:
40
+ def fulfill(self) -> List[SystemdUnitStopItemStopOutcome]:
41
41
  """Fulfill outcomes."""
42
- for outcome in self.outcomes:
42
+ outcomes = self.outcomes
43
+
44
+ for outcome in outcomes:
43
45
  outcome.unit.stop()
44
46
 
47
+ return outcomes
48
+
45
49
  def __eq__(self, other: object) -> bool:
46
50
  """Get equality based on attributes."""
47
51
  if not isinstance(other, SystemdUnitStopItem):
@@ -43,11 +43,15 @@ class UnlinkItem(_Item):
43
43
 
44
44
  return outcomes
45
45
 
46
- def fulfill(self) -> None:
46
+ def fulfill(self) -> List[UnlinkItemUnlinkOutcome]:
47
47
  """Fulfill outcomes."""
48
- for outcome in self.outcomes:
48
+ outcomes = self.outcomes
49
+
50
+ for outcome in outcomes:
49
51
  os.unlink(outcome.path)
50
52
 
53
+ return outcomes
54
+
51
55
  def __eq__(self, other: object) -> bool:
52
56
  """Get equality based on attributes."""
53
57
  if not isinstance(other, UnlinkItem):
@@ -10,7 +10,7 @@ class CopyItemCopyOutcome(OutcomeInterface):
10
10
  """Represents outcome."""
11
11
 
12
12
  def __init__(
13
- self, *, source: str, destination: str, changed_lines: list[str]
13
+ self, *, source: str, destination: str, changed_lines: Optional[list[str]] = None
14
14
  ) -> None:
15
15
  """Set attributes."""
16
16
  self.source = source
@@ -19,10 +19,13 @@ class CopyItemCopyOutcome(OutcomeInterface):
19
19
 
20
20
  def __str__(self) -> str:
21
21
  """Get human-readable string."""
22
- changed_lines = "\n".join(self.changed_lines)
22
+ if self.changed_lines:
23
+ changed_lines = "\nChanged lines:\n" + "\n".join(self.changed_lines)
24
+ else:
25
+ changed_lines = ""
23
26
 
24
27
  return (
25
- f"Copy {self.source} to {self.destination}.\nChanged_lines:\n{changed_lines}"
28
+ f"Copy {self.source} to {self.destination}.{changed_lines}"
26
29
  )
27
30
 
28
31
  def __eq__(self, other: object) -> bool:
@@ -1,11 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python3-cyberfusion-queue-support
3
- Version: 1.6
3
+ Version: 2.0
4
4
  Summary: Library to queue actions.
5
5
  Author-email: Cyberfusion <support@cyberfusion.io>
6
6
  Project-URL: Source, https://github.com/CyberfusionIO/python3-cyberfusion-queue-support
7
7
  Description-Content-Type: text/markdown
8
8
  Requires-Dist: python3-cyberfusion-systemd-support~=2.1
9
+ Requires-Dist: alembic==1.8.1
10
+ Requires-Dist: SQLAlchemy==1.4.46
9
11
 
10
12
  # python3-cyberfusion-queue-support
11
13
 
@@ -2,6 +2,7 @@ README.md
2
2
  pyproject.toml
3
3
  setup.cfg
4
4
  src/cyberfusion/QueueSupport/__init__.py
5
+ src/cyberfusion/QueueSupport/database.py
5
6
  src/cyberfusion/QueueSupport/interfaces.py
6
7
  src/cyberfusion/QueueSupport/outcomes.py
7
8
  src/cyberfusion/QueueSupport/utilities.py
@@ -1 +1,3 @@
1
1
  python3-cyberfusion-systemd-support~=2.1
2
+ alembic==1.8.1
3
+ SQLAlchemy==1.4.46
@@ -1,72 +0,0 @@
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("Added item to queue (reference: '%s')", item.reference)
26
- else:
27
- # If item already in queue, move to last place
28
-
29
- if move_duplicate_last:
30
- self.items.append(self.items.pop(self.items.index(item)))
31
-
32
- logger.info(
33
- "Added item to queue (reference: '%s') (moving duplicate last)",
34
- item.reference,
35
- )
36
- else:
37
- logger.info(
38
- "Didn't add item to queue (reference: '%s') (already present)",
39
- item.reference,
40
- )
41
-
42
- def process(self, preview: bool) -> List[OutcomeInterface]:
43
- """Process items."""
44
- logger.info("Processing items")
45
-
46
- results = []
47
-
48
- for item in self.items:
49
- logger.info("Processing item '%s'", item.reference)
50
-
51
- if not item.hide_outcomes:
52
- results.extend(item.outcomes)
53
-
54
- if not preview:
55
- try:
56
- logger.info("Fulfilling item '%s'", item.reference)
57
-
58
- item.fulfill()
59
-
60
- logger.info("Fulfilled item '%s'", item.reference)
61
- except QueueFulfillFailed:
62
- raise
63
- except Exception as e:
64
- raise QueueFulfillFailed(
65
- item,
66
- ) from e
67
-
68
- logger.info("Processed item '%s'", item.reference)
69
-
70
- logger.info("Processed items")
71
-
72
- return results