mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-12-20 07:43:20 +00:00
Release version 0.3.0
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
## [0.3.0] - 2025-12-17
|
||||
|
||||
* - Introduced a layered Docker architecture: Infinito.Nexus now builds on pre-built pkgmgr base images, with a clear separation between base tooling, application source, and runtime logic.
|
||||
- Standardized container paths (`/opt/src/infinito`) and switched to a global virtual environment to ensure reproducible builds and consistent test execution.
|
||||
- Unit and lint tests now run reliably on this new layer model, both locally and in CI.
|
||||
- Refactored build, setup, and deploy workflows to match the new layered design and improve maintainability.
|
||||
|
||||
|
||||
## [0.2.1] - 2025-12-10
|
||||
|
||||
* restored full deployability of the Sphinx app by fixing the application_id scoping bug.
|
||||
|
||||
@@ -1,27 +1,55 @@
|
||||
import os
|
||||
import warnings
|
||||
from typing import Optional
|
||||
|
||||
_SOUND_DISABLED_REASON: Optional[str] = None
|
||||
_SOUND_WARNED: bool = False
|
||||
|
||||
|
||||
def _warn_sound_disabled_once() -> None:
|
||||
"""
|
||||
Emit the 'Sound support disabled' warning at most once per Python process.
|
||||
|
||||
Important:
|
||||
- Do NOT warn at import time (avoids noisy unit test output).
|
||||
- Warn only when a sound function is actually called.
|
||||
"""
|
||||
global _SOUND_WARNED
|
||||
|
||||
if _SOUND_WARNED:
|
||||
return
|
||||
|
||||
if not _SOUND_DISABLED_REASON:
|
||||
return
|
||||
|
||||
_SOUND_WARNED = True
|
||||
warnings.warn(
|
||||
f"Sound support disabled: {_SOUND_DISABLED_REASON}",
|
||||
RuntimeWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
|
||||
class DummySound:
|
||||
@staticmethod
|
||||
def play_start_sound() -> None:
|
||||
pass
|
||||
_warn_sound_disabled_once()
|
||||
|
||||
@staticmethod
|
||||
def play_infinito_intro_sound() -> None:
|
||||
pass
|
||||
_warn_sound_disabled_once()
|
||||
|
||||
@staticmethod
|
||||
def play_finished_successfully_sound() -> None:
|
||||
pass
|
||||
_warn_sound_disabled_once()
|
||||
|
||||
@staticmethod
|
||||
def play_finished_failed_sound() -> None:
|
||||
pass
|
||||
_warn_sound_disabled_once()
|
||||
|
||||
@staticmethod
|
||||
def play_warning_sound() -> None:
|
||||
pass
|
||||
_warn_sound_disabled_once()
|
||||
|
||||
|
||||
try:
|
||||
@@ -210,7 +238,9 @@ try:
|
||||
cls._prepare_and_play(freqs)
|
||||
|
||||
@classmethod
|
||||
def _prepare_and_play(cls, freqs: list[float], durations: list[float] | None = None) -> None:
|
||||
def _prepare_and_play(
|
||||
cls, freqs: list[float], durations: list[float] | None = None
|
||||
) -> None:
|
||||
count = len(freqs)
|
||||
|
||||
if durations is None:
|
||||
@@ -223,5 +253,7 @@ try:
|
||||
cls._play(np.concatenate(waves))
|
||||
|
||||
except ImportError as exc:
|
||||
warnings.warn(f"Sound support disabled: {exc}", RuntimeWarning)
|
||||
# Do NOT warn at import time — this module is used in many unit tests / subprocess calls.
|
||||
# Warn only when a sound method is actually invoked.
|
||||
_SOUND_DISABLED_REASON = str(exc)
|
||||
Sound = DummySound
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "infinito-nexus"
|
||||
version = "0.0.0"
|
||||
version = "0.3.0"
|
||||
description = "Infinito.Nexus"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
@@ -4,7 +4,7 @@ galaxy_info:
|
||||
description: "Installs and links Nextcloud desktop client folders for cloud-integrated user environments."
|
||||
license: "Infinito.Nexus NonCommercial License"
|
||||
license_url: "https://s.infinito.nexus/license"
|
||||
company: |
|
||||
company: |
|
||||
Kevin Veen-Birkenbach
|
||||
Consulting & Coaching Solutions
|
||||
https://www.veen.world
|
||||
@@ -23,5 +23,3 @@ galaxy_info:
|
||||
repository: https://s.infinito.nexus/code
|
||||
issue_tracker_url: https://s.infinito.nexus/issues
|
||||
documentation: "https://docs.infinito.nexus/"
|
||||
|
||||
dependencies: []
|
||||
@@ -3,32 +3,45 @@
|
||||
name: nextcloud-client
|
||||
state: present
|
||||
|
||||
- name: Link homefolders to cloud
|
||||
ansible.builtin.file:
|
||||
src: "{{nextcloud_cloud_directory}}{{ item }}"
|
||||
dest: "{{nextcloud_user_home_directory}}{{ item }}"
|
||||
owner: "{{ users[desktop_username].username }}"
|
||||
group: "{{ users[desktop_username].username }}"
|
||||
state: link
|
||||
force: yes
|
||||
ignore_errors: true # Just temporary @todo remove
|
||||
loop:
|
||||
- Templates
|
||||
- Documents
|
||||
- Videos
|
||||
- Pictures
|
||||
- Music
|
||||
- Desktop
|
||||
- Software
|
||||
- Downloads
|
||||
- Workspaces
|
||||
- Books
|
||||
- Screenshots
|
||||
- name: Initialize dotlinker mapping list
|
||||
ansible.builtin.set_fact:
|
||||
nextcloud_dotlinker_mappings: []
|
||||
|
||||
- name: Link dump folder
|
||||
ansible.builtin.file:
|
||||
src: "{{nextcloud_cloud_directory}}InstantUpload"
|
||||
dest: "{{nextcloud_user_home_directory}}Dump"
|
||||
owner: "{{ users[desktop_username].username }}"
|
||||
group: "{{ users[desktop_username].username }}"
|
||||
state: link
|
||||
- name: Build dotlinker mappings for Nextcloud folders
|
||||
ansible.builtin.set_fact:
|
||||
nextcloud_dotlinker_mappings: >-
|
||||
{{
|
||||
nextcloud_dotlinker_mappings + [
|
||||
{
|
||||
'name': 'nextcloud-' ~ (item | lower),
|
||||
'backend': 'cloud',
|
||||
'src': nextcloud_user_home_directory ~ item,
|
||||
'dest': nextcloud_cloud_directory ~ item
|
||||
}
|
||||
]
|
||||
}}
|
||||
loop: "{{ nextcloud_dotlinker_folders }}"
|
||||
|
||||
- name: Add dump mapping (Dump -> InstantUpload)
|
||||
ansible.builtin.set_fact:
|
||||
nextcloud_dotlinker_mappings: >-
|
||||
{{
|
||||
nextcloud_dotlinker_mappings + [
|
||||
{
|
||||
'name': 'nextcloud-dump',
|
||||
'backend': 'cloud',
|
||||
'src': nextcloud_user_home_directory ~ 'Dump',
|
||||
'dest': nextcloud_cloud_directory ~ 'InstantUpload'
|
||||
}
|
||||
]
|
||||
}}
|
||||
|
||||
- name: Apply Nextcloud folder mappings via dotlinker
|
||||
ansible.builtin.include_role:
|
||||
name: desk-dotlinker
|
||||
vars:
|
||||
dotlinker_user: "{{ users[desktop_username].username }}"
|
||||
dotlinker_config_path: "{{ nextcloud_user_home_directory }}.config/dotlinker/config.yaml"
|
||||
dotlinker_replace: true
|
||||
dotlinker_apply: true
|
||||
dotlinker_mappings: "{{ nextcloud_dotlinker_mappings }}"
|
||||
|
||||
@@ -1,4 +1,17 @@
|
||||
application_id: desk-nextcloud
|
||||
nextcloud_user_home_directory: "/home/{{ users[desktop_username].username }}/"
|
||||
nextcloud_cloud_fqdn: "{{ applications | get_app_conf(application_id, 'credentials.cloud_fqdn') }}"
|
||||
nextcloud_cloud_directory: '{{ nextcloud_user_home_directory }}Clouds/{{nextcloud_cloud_fqdn}}/{{ users[desktop_username].username }}/'
|
||||
nextcloud_cloud_directory: "{{ nextcloud_user_home_directory }}Clouds/{{ nextcloud_cloud_fqdn }}/{{ users[desktop_username].username }}/"
|
||||
|
||||
nextcloud_dotlinker_folders:
|
||||
- Templates
|
||||
- Documents
|
||||
- Videos
|
||||
- Pictures
|
||||
- Music
|
||||
- Desktop
|
||||
- Software
|
||||
- Downloads
|
||||
- Workspaces
|
||||
- Books
|
||||
- Screenshots
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
- sys-bkp-provider
|
||||
- sys-ctl-alm-compose
|
||||
- sys-lock
|
||||
- dev-nix
|
||||
|
||||
- include_tasks: 02_pkgmgr_routines.yml
|
||||
when: backup_docker_to_local_folder is not defined
|
||||
|
||||
@@ -1,19 +1,50 @@
|
||||
- block:
|
||||
- name: "pkgmgr install {{ BKP_DOCKER_2_LOC_PKG }}"
|
||||
include_role:
|
||||
name: pkgmgr-install
|
||||
vars:
|
||||
package_name: "{{ BKP_DOCKER_2_LOC_PKG }}"
|
||||
- name: "Install/update {{ BKP_DOCKER_2_LOC_PKG }} via pkgmgr (nix run)"
|
||||
become: true
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- nix
|
||||
- run
|
||||
- --no-write-lock-file
|
||||
- "github:kevinveenbirkenbach/package-manager#pkgmgr"
|
||||
- --
|
||||
- update
|
||||
- "{{ BKP_DOCKER_2_LOC_PKG }}"
|
||||
- --dependencies
|
||||
- --clone-mode
|
||||
- shallow
|
||||
register: pkgmgr_update_result
|
||||
changed_when: >
|
||||
('already up to date' not in ((pkgmgr_update_result.stdout | default('') | lower)
|
||||
~ ' ' ~ (pkgmgr_update_result.stderr | default('') | lower)))
|
||||
and
|
||||
('no command defined' not in ((pkgmgr_update_result.stdout | default('') | lower)
|
||||
~ ' ' ~ (pkgmgr_update_result.stderr | default('') | lower)))
|
||||
failed_when: >
|
||||
(pkgmgr_update_result.rc != 0)
|
||||
and
|
||||
('no command defined' not in ((pkgmgr_update_result.stdout | default('') | lower)
|
||||
~ ' ' ~ (pkgmgr_update_result.stderr | default('') | lower)))
|
||||
|
||||
- name: "Retrieve {{ BKP_DOCKER_2_LOC_PKG }} path from pkgmgr"
|
||||
command: "pkgmgr path {{ BKP_DOCKER_2_LOC_PKG }}"
|
||||
- name: "Retrieve {{ BKP_DOCKER_2_LOC_PKG }} path via pkgmgr (nix run)"
|
||||
become: true
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- nix
|
||||
- run
|
||||
- --no-write-lock-file
|
||||
- "github:kevinveenbirkenbach/package-manager#pkgmgr"
|
||||
- --
|
||||
- path
|
||||
- "{{ BKP_DOCKER_2_LOC_PKG }}"
|
||||
register: pkgmgr_output
|
||||
changed_when: false
|
||||
|
||||
- name: Set fact for backup_docker_to_local_folder
|
||||
set_fact:
|
||||
backup_docker_to_local_folder: "{{ pkgmgr_output.stdout }}/"
|
||||
ansible.builtin.set_fact:
|
||||
backup_docker_to_local_folder: "{{ (pkgmgr_output.stdout | trim) ~ '/' }}"
|
||||
changed_when: false
|
||||
|
||||
when: backup_docker_to_local_folder is not defined
|
||||
vars:
|
||||
BKP_DOCKER_2_LOC_PKG: backup-docker-to-local
|
||||
|
||||
@@ -6,7 +6,7 @@ configuration:
|
||||
default_push_create_private: True # Default private when creating a new repository with push-to-create.
|
||||
features:
|
||||
matomo: true
|
||||
css: false
|
||||
css: true
|
||||
desktop: true
|
||||
central_database: true
|
||||
ldap: true
|
||||
|
||||
@@ -14,7 +14,8 @@ GITEA_LDAP_AUTH_ARGS:
|
||||
- '--bind-dn "{{ LDAP.DN.ADMINISTRATOR.DATA }}"'
|
||||
- '--bind-password "{{ LDAP.BIND_CREDENTIAL }}"'
|
||||
- '--user-search-base "{{ LDAP.DN.OU.USERS }}"'
|
||||
- '--user-filter "(&(objectClass=inetOrgPerson)(uid=%s))"'
|
||||
- '--user-filter "(&(objectClass=inetOrgPerson)(uid=%s))"'
|
||||
- '--admin-filter "(memberOf=cn={{ application_id }}-administrator,{{ LDAP.DN.OU.ROLES }})"'
|
||||
- '--username-attribute "{{ LDAP.USER.ATTRIBUTES.ID }}"'
|
||||
- '--firstname-attribute "{{ LDAP.USER.ATTRIBUTES.FIRSTNAME }}"'
|
||||
- '--surname-attribute "{{ LDAP.USER.ATTRIBUTES.SURNAME }}"'
|
||||
|
||||
Reference in New Issue
Block a user