This commit is contained in:
Adam Skotarczak 2025-06-27 12:58:02 +02:00
parent d28fc84bae
commit 87fb37fdd5
31 changed files with 3431 additions and 3259 deletions

8
.gitignore vendored
View File

@ -1,4 +1,4 @@
.vscode/ .vscode/
node_modules/ node_modules/
dist/ dist/

View File

@ -1,16 +1,24 @@
# Changelog # Changelog
- **25/06/15** - commit: v0.2.0 - **27/06/15** - commit: v0.3.0
- **Hinzugefügt:** - **Hinzugefügt:**
- [X] git submodule erstellt - [X] Nginx Proxy Manager
- [X] Rust Toolchain Einrichtung
- [X] Rust offline-installation ---
- **25/06/15** - commit: v0.1.0 - **25/06/15** - commit: v0.2.0
- **Hinzugefügt:** - **Hinzugefügt:**
- [X] helix - [X] git submodule erstellt
- [x] desktop.ini - [X] Rust Toolchain Einrichtung
- [X] Rust offline-installation
---
---
- **initial commit**
- **25/06/15** - commit: v0.1.0
- **Hinzugefügt:**
- [X] helix
- [x] desktop.ini
---
- **initial commit**

View File

@ -1 +1 @@
(C) 2025 - Adam Skotarczak <adam@skotarczak.net (C) 2025 - Adam Skotarczak <adam@skotarczak.net

353
README.md
View File

@ -1,175 +1,178 @@
# -= Admin´s Log =- # -= Admin´s Log =-
![Logo Adam Skotarczak](./media/realAscotLogo_128x128.png) ![Logo Adam Skotarczak](./media/realAscotLogo_128x128.png)
Kleine Sammlung von Gedächnissstützen für den privaten und persönlichen Gebrauch. Kleine Sammlung von Gedächnissstützen für den privaten und persönlichen Gebrauch.
Ausserdem befinden sich hier auch viele Artikel die von mir noch nicht vollständig verwertet worden sind. Ausserdem befinden sich hier auch viele Artikel die von mir noch nicht vollständig verwertet worden sind.
Die Artikel sind auch zur Vorbereitung für neue Artikel auf <https://www.ionivation.com> vorgesehen. Die Artikel sind auch zur Vorbereitung für neue Artikel auf <https://www.ionivation.com> vorgesehen.
**origin:** <https://local.ionivation.com/realAscot/adminslog> **origin:** <https://local.ionivation.com/realAscot/adminslog>
## Inhalt ## Inhalt
- [-= Admin´s Log =-](#--admins-log--) - [-= Admin´s Log =-](#--admins-log--)
- [Inhalt](#inhalt) - [Inhalt](#inhalt)
- [Informationen](#informationen) - [Informationen](#informationen)
- [Themen](#themen) - [Themen](#themen)
- [AsciiDoc](#asciidoc) - [AsciiDoc](#asciidoc)
- [Editoren/ IDE´s](#editoren-ides) - [Editoren/ IDE´s](#editoren-ides)
- [Helix](#helix) - [Helix](#helix)
- [Git](#git) - [Git](#git)
- [Markdown](#markdown) - [Markdown](#markdown)
- [Mermaid](#mermaid) - [Mermaid](#mermaid)
- [Mechanik](#mechanik) - [Mechanik](#mechanik)
- [Server](#server) - [Server](#server)
- [Plesk](#plesk) - [Plesk](#plesk)
- [Webserver](#webserver) - [Webserver](#webserver)
- [Windows](#windows) - [Windows](#windows)
- [Programmierung](#programmierung) - [Programmierung](#programmierung)
- [Rust](#rust) - [Rust](#rust)
- [ts - js - node](#ts---js---node) - [ts - js - node](#ts---js---node)
- [Projektinhalt](#projektinhalt) - [Projektinhalt](#projektinhalt)
- [Neue Dokumente](#neue-dokumente) - [Neue Dokumente](#neue-dokumente)
--- ---
## Informationen ## Informationen
Unter `./tools/` befinden sich Programme/ Skripte (aktuell in Typescript und Python) die Markdown-Dateien suchen und daraus ein Verzeichnis erstellen. Unter `./tools/` befinden sich Programme/ Skripte (aktuell in Typescript und Python) die Markdown-Dateien suchen und daraus ein Verzeichnis erstellen.
--- ---
## Themen ## Themen
--- ---
### AsciiDoc ### AsciiDoc
- [Asciidoctor PDF: Kapitel bleibt „Chapter“ Fehleranalyse & Workaround](dokus/asciidoc/asciidoctor-theme-bug-workaround.md) - [Asciidoctor PDF: Kapitel bleibt „Chapter“ Fehleranalyse & Workaround](dokus/asciidoc/asciidoctor-theme-bug-workaround.md)
--- ---
### Editoren/ IDE´s ### Editoren/ IDE´s
#### Helix #### Helix
- [Helix Editor Ein umfassender Einstieg für Anfänger (Deutsch)](dokus/helix__editor_einfuehrung_de.md) - [Helix Editor Ein umfassender Einstieg für Anfänger (Deutsch)](dokus/helix__editor_einfuehrung_de.md)
--- ---
### Git ### Git
- [Artikel: git](dokus/git/git.md) - [Artikel: git](dokus/git/git.md)
- [SSH-Zugriff auf Git-Repository in WSL einrichten](dokus/git/git-ssh-remote.md) - [SSH-Zugriff auf Git-Repository in WSL einrichten](dokus/git/git-ssh-remote.md)
- [Git Remote-Branches: Häufige Aufgaben und Lösungen](dokus/git/git-remote-branch.md) - [Git Remote-Branches: Häufige Aufgaben und Lösungen](dokus/git/git-remote-branch.md)
- [Git-Submodule: Der umfassende Praxisleitfaden](dokus/git/git-submodule-leitfaden.md) - [Git-Submodule: Der umfassende Praxisleitfaden](dokus/git/git-submodule-leitfaden.md)
### Markdown ### Markdown
#### Mermaid #### Mermaid
- [mermaidPockedGuide](https://local.ionivation.com/realAscot/mermaidPockedGuide) **EXTERN** 🚀 - [mermaidPockedGuide](https://local.ionivation.com/realAscot/mermaidPockedGuide) **EXTERN** 🚀
### Mechanik ### Mechanik
- [Gewindetabellen](dokus/mechanik/gewindetabellen.md) - [Gewindetabellen](dokus/mechanik/gewindetabellen.md)
--- ---
### Server ### Server
#### Plesk #### Plesk
- [Plesk ausgesperrt bei Rechnerwechsel](dokus/plesk/plesk-benutzer-schon-vorhanden.md) - [Plesk ausgesperrt bei Rechnerwechsel](dokus/plesk/plesk-benutzer-schon-vorhanden.md)
#### Webserver #### Webserver
- [Let's Encrypt: Fehlerbehebung bei Challenge-Timeout unter Plesk](dokus/apache-plesk/lets-encrypt-plesk.md) - [Let's Encrypt: Fehlerbehebung bei Challenge-Timeout unter Plesk](dokus/plesk/lets-encrypt-plesk.md)
- [NGINX Proxy Manager als Reverse Proxy für Node.js-Apps](dokus/webserver/nginx-proxy-manager-setup.md)
---
---
### Windows
### Windows
- [Einführung in die `desktop.ini`-Datei: Verwendung und Anpassung von Ordnern in Windows](dokus/windows/desktop_ini.md)
- [Einführung in die `desktop.ini`-Datei: Verwendung und Anpassung von Ordnern in Windows](dokus/windows/desktop_ini.md)
---
---
### Programmierung
### Programmierung
#### Rust
#### Rust
- [Rust-Toolchain mit MSVC unter Windows einrichten](dokus/rust/rust-toolchain-msvc.md)
- [Erstellung eines Installationsmediums für Rust + MSVC (Offline)](dokus/rust/rust-offline-installation.md) - [Rust-Toolchain mit MSVC unter Windows einrichten](dokus/rust/rust-toolchain-msvc.md)
- [Erstellung eines Installationsmediums für Rust + MSVC (Offline)](dokus/rust/rust-offline-installation.md)
---
---
#### ts - js - node
#### ts - js - node
- [Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration](dokus/js-ts/js-ts-dialekte.md)
- [Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration](dokus/js-ts/js-ts-dialekte.md)
---
---
## Projektinhalt
## Projektinhalt
*Erstellt mit [treescanner](https://github.com/realAscot/treeScanner)*
*Erstellt mit [treescanner](https://github.com/realAscot/treeScanner)*
```plaintext
📁 ./ ```plaintext
├── 📁 dokus 📁 ./
│ ├── 📁 apache-plesk ├── 📁 dokus
│ │ └── 📄 lets-encrypt-plesk.md │ ├── 📁 apache-plesk
│ ├── 📁 asciidoc │ │ └── 📄 lets-encrypt-plesk.md
│ │ └── 📄 asciidoctor-theme-bug-workaround.md │ ├── 📁 asciidoc
│ ├── 📁 git │ │ └── 📄 asciidoctor-theme-bug-workaround.md
│ │ ├── 📄 git-remote-branch.md │ ├── 📁 git
│ │ ├── 📄 git-ssh-remote.md │ │ ├── 📄 git-remote-branch.md
│ │ ├── 📄 git-submodule-leitfaden.md │ │ ├── 📄 git-ssh-remote.md
│ │ └── 📄 git.md │ │ ├── 📄 git-submodule-leitfaden.md
│ ├── 📁 js-ts │ │ └── 📄 git.md
│ │ └── 📄 js-ts-dialekte.md │ ├── 📁 js-ts
│ ├── 📁 mechanik │ │ └── 📄 js-ts-dialekte.md
│ │ └── 📄 gewindetabellen.md │ ├── 📁 mechanik
│ ├── 📁 plesk │ │ └── 📄 gewindetabellen.md
│ │ └── 📄 plesk-benutzer-schon-vorhanden.md │ ├── 📁 plesk
│ ├── 📁 rust │ │ └── 📄 plesk-benutzer-schon-vorhanden.md
│ │ ├── 📄 rust-offline-installation.md │ ├── 📁 rust
│ │ └── 📄 rust-toolchain-msvc.md │ │ ├── 📄 rust-offline-installation.md
│ ├── 📁 windows │ │ └── 📄 rust-toolchain-msvc.md
│ │ └── 📄 desktop_ini.md │ ├── 📁 windows
│ └── 📄 helix__editor_einfuehrung_de.md │ │ └── 📄 desktop_ini.md
├── 📁 media │ └── 📄 helix__editor_einfuehrung_de.md
│ └── 📄 realAscotLogo_128x128.png ├── 📁 media
├── 📁 tools │ └── 📄 realAscotLogo_128x128.png
│ ├── 📁 collector ├── 📁 tools
│ │ ├── 📄 config.jsonc │ ├── 📁 collector
│ │ ├── 📄 link_collector.js │ │ ├── 📄 config.jsonc
│ │ ├── 📄 link_collector.py │ │ ├── 📄 link_collector.js
│ │ └── 📄 processed.log │ │ ├── 📄 link_collector.py
│ ├── 📁 dist │ │ └── 📄 processed.log
│ │ ├── 📁 collector │ ├── 📁 dist
│ │ ├── 📄 fscopy.js │ │ ├── 📁 collector
│ │ └── 📄 fsdel.js │ │ ├── 📄 fscopy.js
│ └── 📁 src │ │ └── 📄 fsdel.js
│ ├── 📁 collector │ └── 📁 src
│ │ ├── 📄 config.jsonc.template │ ├── 📁 collector
│ │ └── 📄 link_collector.ts │ │ ├── 📄 config.jsonc.template
│ ├── 📄 fscopy.ts │ │ └── 📄 link_collector.ts
│ └── 📄 fsdel.ts │ ├── 📄 fscopy.ts
├── 📄 .gitignore │ └── 📄 fsdel.ts
├── 📄 CHANGELOG.md ├── 📄 .gitignore
├── 📄 LICENSE ├── 📄 CHANGELOG.md
├── 📄 package-lock.json ├── 📄 LICENSE
├── 📄 package.json ├── 📄 package-lock.json
├── 📄 README.md ├── 📄 package.json
├── 📄 scan.cmd ├── 📄 README.md
├── 📄 tsconfig.json ├── 📄 scan.cmd
└── 📄 VERSION ├── 📄 tsconfig.json
``` └── 📄 VERSION
```
---
---
## Neue Dokumente
## Neue Dokumente
> führe `scan.cmd` oder [`link_collector.py`](./tools/collector/link_collector.py) oder `npm run scan` aus um nach neuen Dateien zu suchen!
> führe `scan.cmd` oder [`link_collector.py`](./tools/collector/link_collector.py) oder `npm run scan` aus um nach neuen Dateien zu suchen!
**NEUE EINTRÄGE AUS 'link_collector'->**
**NEUE EINTRÄGE AUS 'link_collector'->**
---

View File

@ -1,2 +1,2 @@
0.2.0 0.3.0
15.06.2025 27.06.2025

View File

@ -1,82 +1,82 @@
# Asciidoctor PDF: Kapitel bleibt „Chapter“ Fehleranalyse & Workaround # Asciidoctor PDF: Kapitel bleibt „Chapter“ Fehleranalyse & Workaround
## 🧩 Problem ## 🧩 Problem
Beim Generieren von PDFs mit `asciidoctor-pdf` (Version 2.3.19) wird die Kapitelüberschrift trotz korrekt gesetztem deutschen Theme und Sprache **nicht lokalisiert**: Beim Generieren von PDFs mit `asciidoctor-pdf` (Version 2.3.19) wird die Kapitelüberschrift trotz korrekt gesetztem deutschen Theme und Sprache **nicht lokalisiert**:
```text ```text
Chapter 1. Einführung Chapter 1. Einführung
``` ```
…statt: …statt:
```text ```text
Kapitel 1. Einführung Kapitel 1. Einführung
``` ```
--- ---
## ✅ Erwartete Konfiguration ## ✅ Erwartete Konfiguration
Folgendes wurde korrekt gesetzt: Folgendes wurde korrekt gesetzt:
- `chapter.title: "Kapitel {counter:chapter-number}. "` im Theme - `chapter.title: "Kapitel {counter:chapter-number}. "` im Theme
- `locale: lang` im Theme - `locale: lang` im Theme
- Fonts korrekt eingebunden - Fonts korrekt eingebunden
- `:lang: de` entfernt aus `.adoc` (zur Sicherheit) - `:lang: de` entfernt aus `.adoc` (zur Sicherheit)
- Keine `de.yml` verwendet - Keine `de.yml` verwendet
- Keine Snap-Version oder Paketkonflikte - Keine Snap-Version oder Paketkonflikte
- Theme definitiv geladen (`font_size`, `base`, etc. wirksam) - Theme definitiv geladen (`font_size`, `base`, etc. wirksam)
--- ---
## ❌ Ergebnis ## ❌ Ergebnis
Trotz aller Korrektheit: Trotz aller Korrektheit:
- Ausgabe bleibt auf Englisch - Ausgabe bleibt auf Englisch
- Lokalisierung über Theme wird ignoriert - Lokalisierung über Theme wird ignoriert
- Das Verhalten ist **reproduzierbar auf mehreren Rechnern und Installationen** - Das Verhalten ist **reproduzierbar auf mehreren Rechnern und Installationen**
--- ---
## 🧨 Vermutete Ursache ## 🧨 Vermutete Ursache
Ein Bug oder ein Regressionseffekt in `asciidoctor-pdf` ab Version `2.3.0`, bei dem: Ein Bug oder ein Regressionseffekt in `asciidoctor-pdf` ab Version `2.3.0`, bei dem:
- entweder `chapter.title` aus Theme nicht mehr greift - entweder `chapter.title` aus Theme nicht mehr greift
- oder durch eine andere Sprachverarbeitung überschrieben wird - oder durch eine andere Sprachverarbeitung überschrieben wird
--- ---
## ✅ Workaround ## ✅ Workaround
Statt auf automatische Kapitelüberschriften zu setzen, diese manuell überschreiben: Statt auf automatische Kapitelüberschriften zu setzen, diese manuell überschreiben:
### Im `.adoc`: ### Im `.adoc`:
```asciidoc ```asciidoc
:sectnums!: :sectnums!:
[discrete] [discrete]
== Kapitel 1. Einführung == Kapitel 1. Einführung
``` ```
→ So wird die Kapitelzeile manuell gesetzt und `sectnums` deaktiviert. → So wird die Kapitelzeile manuell gesetzt und `sectnums` deaktiviert.
--- ---
## 📌 Empfehlung ## 📌 Empfehlung
- In Projekten mit PDF-Export: Immer testen, ob `theme.yml` wirklich angewendet wird - In Projekten mit PDF-Export: Immer testen, ob `theme.yml` wirklich angewendet wird
- Optional: eigene `make test-theme` Ziel im Makefile zur Überprüfung einbauen - Optional: eigene `make test-theme` Ziel im Makefile zur Überprüfung einbauen
- Bis Bug behoben ist: Kapitel manuell beschriften oder alternative Engine verwenden - Bis Bug behoben ist: Kapitel manuell beschriften oder alternative Engine verwenden
--- ---
## 🔗 Betroffene Versionen ## 🔗 Betroffene Versionen
- `asciidoctor-pdf 2.3.19` - `asciidoctor-pdf 2.3.19`
- `asciidoctor 2.0.23` - `asciidoctor 2.0.23`
- `ruby 3.1.x` - `ruby 3.1.x`
- UTF-8 / Linux / WSL identisches Verhalten - UTF-8 / Linux / WSL identisches Verhalten

View File

@ -1,162 +1,162 @@
# Git Remote-Branches: Häufige Aufgaben und Lösungen # Git Remote-Branches: Häufige Aufgaben und Lösungen
**Stand:** 2025-05-26 **Stand:** 2025-05-26
> Diese Anleitung erklärt, wie man mit Remote-Branches arbeitet insbesondere dann, wenn der Branch lokal noch nicht existiert oder gezielt ressourcenschonend gearbeitet werden soll. > Diese Anleitung erklärt, wie man mit Remote-Branches arbeitet insbesondere dann, wenn der Branch lokal noch nicht existiert oder gezielt ressourcenschonend gearbeitet werden soll.
--- ---
## 📌 Inhalt ## 📌 Inhalt
- [Git Remote-Branches: Häufige Aufgaben und Lösungen](#git--remote-branches-häufige-aufgaben-und-lösungen) - [Git Remote-Branches: Häufige Aufgaben und Lösungen](#git--remote-branches-häufige-aufgaben-und-lösungen)
- [📌 Inhalt](#-inhalt) - [📌 Inhalt](#-inhalt)
- [❓ 1. Wie hole ich einen Remote-Branch, den ich lokal noch nicht habe?](#-1-wie-hole-ich-einen-remote-branch-den-ich-lokal-noch-nicht-habe) - [❓ 1. Wie hole ich einen Remote-Branch, den ich lokal noch nicht habe?](#-1-wie-hole-ich-einen-remote-branch-den-ich-lokal-noch-nicht-habe)
- [❓ 2. Warum sehe ich den Remote-Branch nicht in `git branch -r`?](#-2-warum-sehe-ich-den-remote-branch-nicht-in-git-branch--r) - [❓ 2. Warum sehe ich den Remote-Branch nicht in `git branch -r`?](#-2-warum-sehe-ich-den-remote-branch-nicht-in-git-branch--r)
- [❓ 3. Holt `git clone` automatisch alle Branches?](#-3-holt-git-clone-automatisch-alle-branches) - [❓ 3. Holt `git clone` automatisch alle Branches?](#-3-holt-git-clone-automatisch-alle-branches)
- [❓ 4. Wie klone ich gezielt nur einen bestimmten Branch?](#-4-wie-klone-ich-gezielt-nur-einen-bestimmten-branch) - [❓ 4. Wie klone ich gezielt nur einen bestimmten Branch?](#-4-wie-klone-ich-gezielt-nur-einen-bestimmten-branch)
- [❓ 5. Wann ist `--single-branch` sinnvoll?](#-5-wann-ist---single-branch-sinnvoll) - [❓ 5. Wann ist `--single-branch` sinnvoll?](#-5-wann-ist---single-branch-sinnvoll)
- [❓ 6. Wie sehe ich alle Remote-Branches **vor** dem Clonen?](#-6-wie-sehe-ich-alle-remote-branches-vor-dem-clonen) - [❓ 6. Wie sehe ich alle Remote-Branches **vor** dem Clonen?](#-6-wie-sehe-ich-alle-remote-branches-vor-dem-clonen)
- [🛠️ Optionaler Alias-Tipp](#-optionaler-alias-tipp) - [🛠️ Optionaler Alias-Tipp](#-optionaler-alias-tipp)
- [🧠 Zusammenfassung](#-zusammenfassung) - [🧠 Zusammenfassung](#-zusammenfassung)
--- ---
## ❓ 1. Wie hole ich einen Remote-Branch, den ich lokal noch nicht habe? ## ❓ 1. Wie hole ich einen Remote-Branch, den ich lokal noch nicht habe?
```bash ```bash
git fetch git fetch
git checkout -b <lokaler-name> origin/<remote-branch> git checkout -b <lokaler-name> origin/<remote-branch>
``` ```
Alternativ automatisch als Tracking-Branch: Alternativ automatisch als Tracking-Branch:
```bash ```bash
git checkout --track origin/<remote-branch> git checkout --track origin/<remote-branch>
``` ```
Beispiel: Beispiel:
```bash ```bash
git checkout --track origin/feature/chat-system git checkout --track origin/feature/chat-system
``` ```
--- ---
## ❓ 2. Warum sehe ich den Remote-Branch nicht in `git branch -r`? ## ❓ 2. Warum sehe ich den Remote-Branch nicht in `git branch -r`?
`git branch -r` zeigt nur die lokal bekannten Remote-Refs. `git branch -r` zeigt nur die lokal bekannten Remote-Refs.
Du musst vorher `git fetch` ausführen: Du musst vorher `git fetch` ausführen:
```bash ```bash
git fetch git fetch
git branch -r git branch -r
``` ```
Optional: erzwungen alles holen: Optional: erzwungen alles holen:
```bash ```bash
git fetch origin '+refs/heads/*:refs/remotes/origin/*' git fetch origin '+refs/heads/*:refs/remotes/origin/*'
``` ```
--- ---
## ❓ 3. Holt `git clone` automatisch alle Branches? ## ❓ 3. Holt `git clone` automatisch alle Branches?
**Nicht ganz.** `git clone`: **Nicht ganz.** `git clone`:
- ✅ holt alle Branches als Referenzen - ✅ holt alle Branches als Referenzen
- ❌ checkt nur den Standard-Branch (z.B. `main`) lokal aus - ❌ checkt nur den Standard-Branch (z.B. `main`) lokal aus
**Weitere Branches** müssen manuell ausgecheckt werden: **Weitere Branches** müssen manuell ausgecheckt werden:
```bash ```bash
git checkout --track origin/<branch-name> git checkout --track origin/<branch-name>
``` ```
Optional zur Sicherheit vorher: Optional zur Sicherheit vorher:
```bash ```bash
git fetch git fetch
git branch -r git branch -r
``` ```
--- ---
## ❓ 4. Wie klone ich gezielt nur einen bestimmten Branch? ## ❓ 4. Wie klone ich gezielt nur einen bestimmten Branch?
Nur den gewünschten Branch klonen (kein anderer wird geholt): Nur den gewünschten Branch klonen (kein anderer wird geholt):
```bash ```bash
git clone --branch <branch-name> --single-branch <repo-url> git clone --branch <branch-name> --single-branch <repo-url>
``` ```
Mit reduziertem Verlauf (nur letzte Commits): Mit reduziertem Verlauf (nur letzte Commits):
```bash ```bash
git clone --branch <branch-name> --single-branch --depth 1 <repo-url> git clone --branch <branch-name> --single-branch --depth 1 <repo-url>
``` ```
--- ---
## ❓ 5. Wann ist `--single-branch` sinnvoll? ## ❓ 5. Wann ist `--single-branch` sinnvoll?
Diese Variante ist ideal, wenn: Diese Variante ist ideal, wenn:
- du **nur an einem Branch arbeiten** willst - du **nur an einem Branch arbeiten** willst
- du **Platz oder Zeit sparen** möchtest - du **Platz oder Zeit sparen** möchtest
- du das Repo **später einfach löschen** willst - du das Repo **später einfach löschen** willst
- du z.B. in **CI/CD**, **Docker**, **VMs** oder **temporär lokal** arbeitest - du z.B. in **CI/CD**, **Docker**, **VMs** oder **temporär lokal** arbeitest
Sie vermeidet unnötige Daten und beschleunigt den Clone-Prozess. Sie vermeidet unnötige Daten und beschleunigt den Clone-Prozess.
--- ---
## ❓ 6. Wie sehe ich alle Remote-Branches **vor** dem Clonen? ## ❓ 6. Wie sehe ich alle Remote-Branches **vor** dem Clonen?
Du kannst dir **alle Branches am Remote-Repo anzeigen lassen**, ohne zu klonen: Du kannst dir **alle Branches am Remote-Repo anzeigen lassen**, ohne zu klonen:
```bash ```bash
git ls-remote --heads <repo-url> git ls-remote --heads <repo-url>
``` ```
Beispiel: Beispiel:
```bash ```bash
git ls-remote --heads ssh://git@local.ionivation.com:2222/codewalker/codewalker.net.git git ls-remote --heads ssh://git@local.ionivation.com:2222/codewalker/codewalker.net.git
``` ```
Ergebnis: Ergebnis:
```text ```text
f3a91d... refs/heads/main f3a91d... refs/heads/main
c4bd79... refs/heads/feature/chat-system c4bd79... refs/heads/feature/chat-system
``` ```
--- ---
## 🛠️ Optionaler Alias-Tipp ## 🛠️ Optionaler Alias-Tipp
Wenn du häufig neue Branches holen willst: Wenn du häufig neue Branches holen willst:
```bash ```bash
git config --global alias.fr 'fetch && branch -r' git config --global alias.fr 'fetch && branch -r'
``` ```
Verwendung: Verwendung:
```bash ```bash
git fr git fr
``` ```
= `git fetch` + Anzeige aller Remote-Branches = `git fetch` + Anzeige aller Remote-Branches
--- ---
## 🧠 Zusammenfassung ## 🧠 Zusammenfassung
| Ziel | Befehl | | Ziel | Befehl |
|-------------------------------------|------------------------------------------------------| |-------------------------------------|------------------------------------------------------|
| Remote-Branch holen + auschecken | `git fetch` + `git checkout --track origin/<name>` | | Remote-Branch holen + auschecken | `git fetch` + `git checkout --track origin/<name>` |
| Nur einen Branch klonen | `git clone --branch <name> --single-branch <url>` | | Nur einen Branch klonen | `git clone --branch <name> --single-branch <url>` |
| Branchliste ohne Clone anzeigen | `git ls-remote --heads <repo-url>` | | Branchliste ohne Clone anzeigen | `git ls-remote --heads <repo-url>` |
| Lokale Sichtbarkeit Remote-Branches | `git fetch` + `git branch -r` | | Lokale Sichtbarkeit Remote-Branches | `git fetch` + `git branch -r` |

View File

@ -1,194 +1,194 @@
# SSH-Zugriff auf Git-Repository in WSL einrichten # SSH-Zugriff auf Git-Repository in WSL einrichten
Diese Anleitung beschreibt, wie man innerhalb von WSL (z.B. Ubuntu) ein Git-Repository per SSH nutzen kann, z.B. bei einem selbst gehosteten Gitea-Server auf `dns.lan` mit Port `2222`. Diese Anleitung beschreibt, wie man innerhalb von WSL (z.B. Ubuntu) ein Git-Repository per SSH nutzen kann, z.B. bei einem selbst gehosteten Gitea-Server auf `dns.lan` mit Port `2222`.
- [SSH-Zugriff auf Git-Repository in WSL einrichten](#ssh-zugriff-auf-git-repository-in-wsl-einrichten) - [SSH-Zugriff auf Git-Repository in WSL einrichten](#ssh-zugriff-auf-git-repository-in-wsl-einrichten)
- [🔧 Voraussetzungen](#-voraussetzungen) - [🔧 Voraussetzungen](#-voraussetzungen)
- [🧱 Schritt 1: SSH-Verzeichnis in WSL anlegen](#-schritt-1-ssh-verzeichnis-in-wsl-anlegen) - [🧱 Schritt 1: SSH-Verzeichnis in WSL anlegen](#-schritt-1-ssh-verzeichnis-in-wsl-anlegen)
- [🗝️ Schritt 2: SSH-Schlüssel aus Windows in WSL übernehmen](#-schritt-2-ssh-schlüssel-aus-windows-in-wsl-übernehmen) - [🗝️ Schritt 2: SSH-Schlüssel aus Windows in WSL übernehmen](#-schritt-2-ssh-schlüssel-aus-windows-in-wsl-übernehmen)
- [⚙️ Schritt 3: SSH-Konfiguration (optional, empfohlen)](#-schritt-3-ssh-konfiguration-optional-empfohlen) - [⚙️ Schritt 3: SSH-Konfiguration (optional, empfohlen)](#-schritt-3-ssh-konfiguration-optional-empfohlen)
- [🧪 Schritt 4: Verbindung testen](#-schritt-4-verbindung-testen) - [🧪 Schritt 4: Verbindung testen](#-schritt-4-verbindung-testen)
- [🐙 Schritt 5: Git-Remote setzen oder klonen](#-schritt-5-git-remote-setzen-oder-klonen) - [🐙 Schritt 5: Git-Remote setzen oder klonen](#-schritt-5-git-remote-setzen-oder-klonen)
- [✅ Bestehendes Repo umstellen](#-bestehendes-repo-umstellen) - [✅ Bestehendes Repo umstellen](#-bestehendes-repo-umstellen)
- [✅ Neues Repo klonen](#-neues-repo-klonen) - [✅ Neues Repo klonen](#-neues-repo-klonen)
- [🛡️ Hinweis: Keine Shell-Zugänge über Git-SSH](#-hinweis-keine-shell-zugänge-über-git-ssh) - [🛡️ Hinweis: Keine Shell-Zugänge über Git-SSH](#-hinweis-keine-shell-zugänge-über-git-ssh)
- [✅ Fertig](#-fertig) - [✅ Fertig](#-fertig)
- [🔁 Optional: Globale Git-Konfiguration absichern](#-optional-globale-git-konfiguration-absichern) - [🔁 Optional: Globale Git-Konfiguration absichern](#-optional-globale-git-konfiguration-absichern)
- [🔑 SSH-Key unter WSL erzeugen](#-ssh-key-unter-wsl-erzeugen) - [🔑 SSH-Key unter WSL erzeugen](#-ssh-key-unter-wsl-erzeugen)
- [🛠️ Voraussetzungen installieren](#-voraussetzungen-installieren) - [🛠️ Voraussetzungen installieren](#-voraussetzungen-installieren)
- [🔐 SSH-Key erzeugen](#-ssh-key-erzeugen) - [🔐 SSH-Key erzeugen](#-ssh-key-erzeugen)
- [⌨️ Bei der Abfrage:](#-bei-der-abfrage) - [⌨️ Bei der Abfrage:](#-bei-der-abfrage)
- [🔍 Public Key anzeigen](#-public-key-anzeigen) - [🔍 Public Key anzeigen](#-public-key-anzeigen)
- [✅ Optional: SSH-Agent starten \& Schlüssel hinzufügen](#-optional-ssh-agent-starten--schlüssel-hinzufügen) - [✅ Optional: SSH-Agent starten \& Schlüssel hinzufügen](#-optional-ssh-agent-starten--schlüssel-hinzufügen)
--- ---
## 🔧 Voraussetzungen ## 🔧 Voraussetzungen
- WSL ist eingerichtet (z.B. Ubuntu) - WSL ist eingerichtet (z.B. Ubuntu)
- Ein Git-Server ist erreichbar (z.B. `git@dns.lan:2222`) - Ein Git-Server ist erreichbar (z.B. `git@dns.lan:2222`)
- Du hast bereits Zugriff über Windows (z.B. via PowerShell) - Du hast bereits Zugriff über Windows (z.B. via PowerShell)
- OpenSSH ist in der WSL-Distribution installiert - OpenSSH ist in der WSL-Distribution installiert
- Wenn Du noch keinen Key hast oder einen neuen einrichten möchtest, gibt es unten unter [🔑 SSH-Key unter WSL erzeugen](#-ssh-key-unter-wsl-erzeugen) nochmal eine Auffrischung. - Wenn Du noch keinen Key hast oder einen neuen einrichten möchtest, gibt es unten unter [🔑 SSH-Key unter WSL erzeugen](#-ssh-key-unter-wsl-erzeugen) nochmal eine Auffrischung.
--- ---
## 🧱 Schritt 1: SSH-Verzeichnis in WSL anlegen ## 🧱 Schritt 1: SSH-Verzeichnis in WSL anlegen
```bash ```bash
mkdir -p ~/.ssh mkdir -p ~/.ssh
chmod 700 ~/.ssh chmod 700 ~/.ssh
``` ```
--- ---
## 🗝️ Schritt 2: SSH-Schlüssel aus Windows in WSL übernehmen ## 🗝️ Schritt 2: SSH-Schlüssel aus Windows in WSL übernehmen
Falls du in Windows bereits einen Schlüssel hast, z.B. `C:\Users\NAME\.ssh\id_ed25519`, kopiere ihn: Falls du in Windows bereits einen Schlüssel hast, z.B. `C:\Users\NAME\.ssh\id_ed25519`, kopiere ihn:
```bash ```bash
cp /mnt/c/Users/NAME/.ssh/id_ed25519 ~/.ssh/ cp /mnt/c/Users/NAME/.ssh/id_ed25519 ~/.ssh/
cp /mnt/c/Users/NAME/.ssh/id_ed25519.pub ~/.ssh/ cp /mnt/c/Users/NAME/.ssh/id_ed25519.pub ~/.ssh/
chmod 600 ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub chmod 644 ~/.ssh/id_ed25519.pub
``` ```
🔁 Ersetze `NAME` mit deinem Windows-Benutzernamen. 🔁 Ersetze `NAME` mit deinem Windows-Benutzernamen.
--- ---
## ⚙️ Schritt 3: SSH-Konfiguration (optional, empfohlen) ## ⚙️ Schritt 3: SSH-Konfiguration (optional, empfohlen)
Erstelle (oder bearbeite) die Datei `~/.ssh/config`: Erstelle (oder bearbeite) die Datei `~/.ssh/config`:
```bash ```bash
nano ~/.ssh/config nano ~/.ssh/config
``` ```
Füge ein: Füge ein:
```ssh ```ssh
Host gitea Host gitea
HostName dns.lan HostName dns.lan
Port 2222 Port 2222
User git User git
IdentityFile ~/.ssh/id_ed25519 IdentityFile ~/.ssh/id_ed25519
``` ```
→ Damit kannst du den Hostname `gitea` als Alias verwenden. → Damit kannst du den Hostname `gitea` als Alias verwenden.
--- ---
## 🧪 Schritt 4: Verbindung testen ## 🧪 Schritt 4: Verbindung testen
```bash ```bash
ssh -T gitea ssh -T gitea
``` ```
Erwartete Ausgabe: Erwartete Ausgabe:
```text ```text
Hi there, realAscot! You've successfully authenticated... Hi there, realAscot! You've successfully authenticated...
``` ```
--- ---
## 🐙 Schritt 5: Git-Remote setzen oder klonen ## 🐙 Schritt 5: Git-Remote setzen oder klonen
### ✅ Bestehendes Repo umstellen ### ✅ Bestehendes Repo umstellen
```bash ```bash
git remote set-url origin gitea:realAscot/mein-projekt.git git remote set-url origin gitea:realAscot/mein-projekt.git
``` ```
### ✅ Neues Repo klonen ### ✅ Neues Repo klonen
```bash ```bash
git clone gitea:realAscot/mein-projekt.git git clone gitea:realAscot/mein-projekt.git
``` ```
--- ---
## 🛡️ Hinweis: Keine Shell-Zugänge über Git-SSH ## 🛡️ Hinweis: Keine Shell-Zugänge über Git-SSH
Wenn du folgende Meldung siehst: Wenn du folgende Meldung siehst:
```text ```text
You've successfully authenticated, but Gitea does not provide shell access. You've successfully authenticated, but Gitea does not provide shell access.
``` ```
→ Das ist normal und **kein Fehler** Push/Pull funktioniert trotzdem. → Das ist normal und **kein Fehler** Push/Pull funktioniert trotzdem.
--- ---
## ✅ Fertig ## ✅ Fertig
Du kannst jetzt in WSL wie gewohnt per SSH arbeiten: Du kannst jetzt in WSL wie gewohnt per SSH arbeiten:
```bash ```bash
git pull git pull
git push git push
``` ```
--- ---
## 🔁 Optional: Globale Git-Konfiguration absichern ## 🔁 Optional: Globale Git-Konfiguration absichern
```bash ```bash
git config --global core.autocrlf input git config --global core.autocrlf input
git config --global core.eol lf git config --global core.eol lf
``` ```
Damit vermeidest du Konflikte durch Windows-Zeilenenden. Damit vermeidest du Konflikte durch Windows-Zeilenenden.
Hat mit dem SSH Key jetzt nichts zu tun, aber ein kleiner Tipp nebenbei um bekannte Fehler zu vermeiden. Hat mit dem SSH Key jetzt nichts zu tun, aber ein kleiner Tipp nebenbei um bekannte Fehler zu vermeiden.
--- ---
## 🔑 SSH-Key unter WSL erzeugen ## 🔑 SSH-Key unter WSL erzeugen
Hier ist eine kompakte Anleitung in **Markdown**, wie du unter **WSL** (z.B. Ubuntu) einen SSH-Key erzeugst und die nötigen Tools installierst, um z.B. Gitea-Zugriff zu ermöglichen. Hier ist eine kompakte Anleitung in **Markdown**, wie du unter **WSL** (z.B. Ubuntu) einen SSH-Key erzeugst und die nötigen Tools installierst, um z.B. Gitea-Zugriff zu ermöglichen.
### 🛠️ Voraussetzungen installieren ### 🛠️ Voraussetzungen installieren
```bash ```bash
sudo apt update sudo apt update
sudo apt install -y openssh-client sudo apt install -y openssh-client
``` ```
### 🔐 SSH-Key erzeugen ### 🔐 SSH-Key erzeugen
```bash ```bash
ssh-keygen -t ed25519 -C "dein.name@example.com" -f ~/.ssh/id_ed25519_gitea ssh-keygen -t ed25519 -C "dein.name@example.com" -f ~/.ssh/id_ed25519_gitea
``` ```
Der Parameter `-f` gibt den Pfad und Namen des neuen Keys an. Der Parameter `-f` gibt den Pfad und Namen des neuen Keys an.
Wenn man diesen weglässt, überschreibst Du Dir eventuell einen schon vorhandenen Key den Du vielleicht für etwas anderes nutzt! Wenn man diesen weglässt, überschreibst Du Dir eventuell einen schon vorhandenen Key den Du vielleicht für etwas anderes nutzt!
Du wirst dann aber je nach Version nach einem Pfad gefragt. Du wirst dann aber je nach Version nach einem Pfad gefragt.
Besser direkt angeben. Besser direkt angeben.
- **Erklärung:** - **Erklärung:**
- `-t ed25519`: moderner, sicherer Algorithmus - `-t ed25519`: moderner, sicherer Algorithmus
- `-C`: Kommentar (z.B. Mailadresse oder Systembeschreibung) - `-C`: Kommentar (z.B. Mailadresse oder Systembeschreibung)
#### ⌨️ Bei der Abfrage: #### ⌨️ Bei der Abfrage:
- **Dateipfad**: einfach Enter drücken für Standard (`~/.ssh/id_ed25519_gitea`) - **Dateipfad**: einfach Enter drücken für Standard (`~/.ssh/id_ed25519_gitea`)
- **Passphrase**: optional, aber empfohlen (für zusätzliche Sicherheit) - **Passphrase**: optional, aber empfohlen (für zusätzliche Sicherheit)
### 🔍 Public Key anzeigen ### 🔍 Public Key anzeigen
```bash ```bash
cat ~/.ssh/id_ed25519_gitea.pub cat ~/.ssh/id_ed25519_gitea.pub
``` ```
→ Diesen Schlüssel dann in **Gitea unter „SSH-Schlüssel“** einfügen. → Diesen Schlüssel dann in **Gitea unter „SSH-Schlüssel“** einfügen.
### ✅ Optional: SSH-Agent starten & Schlüssel hinzufügen ### ✅ Optional: SSH-Agent starten & Schlüssel hinzufügen
```bash ```bash
eval "$(ssh-agent -s)" eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519_gitea ssh-add ~/.ssh/id_ed25519_gitea
``` ```
--- ---

View File

@ -1,203 +1,203 @@
# Git-Submodule: Der umfassende Praxisleitfaden # Git-Submodule: Der umfassende Praxisleitfaden
## Inhalt ## Inhalt
- [Git-Submodule: Der umfassende Praxisleitfaden](#git-submodule-der-umfassende-praxisleitfaden) - [Git-Submodule: Der umfassende Praxisleitfaden](#git-submodule-der-umfassende-praxisleitfaden)
- [Inhalt](#inhalt) - [Inhalt](#inhalt)
- [🔰 Was ist ein Git-Submodul?](#-was-ist-ein-git-submodul) - [🔰 Was ist ein Git-Submodul?](#-was-ist-ein-git-submodul)
- [🧱 Grundlagen](#-grundlagen) - [🧱 Grundlagen](#-grundlagen)
- [📌 `.gitmodules`](#-gitmodules) - [📌 `.gitmodules`](#-gitmodules)
- [🧠 Merksatz](#-merksatz) - [🧠 Merksatz](#-merksatz)
- [🛠️ Submodul hinzufügen](#-submodul-hinzufügen) - [🛠️ Submodul hinzufügen](#-submodul-hinzufügen)
- [🔄 Submodule aktualisieren](#-submodule-aktualisieren) - [🔄 Submodule aktualisieren](#-submodule-aktualisieren)
- [📥 Klonen mit Submodulen](#-klonen-mit-submodulen) - [📥 Klonen mit Submodulen](#-klonen-mit-submodulen)
- [Methode 1: Inklusive Submodule](#methode-1-inklusive-submodule) - [Methode 1: Inklusive Submodule](#methode-1-inklusive-submodule)
- [Methode 2: Nachträglich initialisieren](#methode-2-nachträglich-initialisieren) - [Methode 2: Nachträglich initialisieren](#methode-2-nachträglich-initialisieren)
- [🔃 Submodul-Synchronisation](#-submodul-synchronisation) - [🔃 Submodul-Synchronisation](#-submodul-synchronisation)
- [📂 Weitere Remotes im Submodul](#-weitere-remotes-im-submodul) - [📂 Weitere Remotes im Submodul](#-weitere-remotes-im-submodul)
- [❗ Stolperfallen und Besonderheiten](#-stolperfallen-und-besonderheiten) - [❗ Stolperfallen und Besonderheiten](#-stolperfallen-und-besonderheiten)
- [🔄 Remote-URL wechseln](#-remote-url-wechseln) - [🔄 Remote-URL wechseln](#-remote-url-wechseln)
- [🚀 Push \& Pull Verhalten](#-push--pull-verhalten) - [🚀 Push \& Pull Verhalten](#-push--pull-verhalten)
- [🧼 Submodul löschen](#-submodul-löschen) - [🧼 Submodul löschen](#-submodul-löschen)
- [🧰 Best Practices](#-best-practices) - [🧰 Best Practices](#-best-practices)
- [📎 Nützliche Kommandos](#-nützliche-kommandos) - [📎 Nützliche Kommandos](#-nützliche-kommandos)
- [📑 Beispiel `.gitmodules` mit kommentierter Remote-Auswahl](#-beispiel-gitmodules-mit-kommentierter-remote-auswahl) - [📑 Beispiel `.gitmodules` mit kommentierter Remote-Auswahl](#-beispiel-gitmodules-mit-kommentierter-remote-auswahl)
- [🧭 Alternative: Subtree statt Submodul?](#-alternative-subtree-statt-submodul) - [🧭 Alternative: Subtree statt Submodul?](#-alternative-subtree-statt-submodul)
- [📚 Fazit](#-fazit) - [📚 Fazit](#-fazit)
- [🔗 Weiterführende Links](#-weiterführende-links) - [🔗 Weiterführende Links](#-weiterführende-links)
--- ---
## 🔰 Was ist ein Git-Submodul? ## 🔰 Was ist ein Git-Submodul?
Ein **Submodul** ist ein Git-Repository innerhalb eines anderen Git-Repositories. Es erlaubt, einen festen Commit eines externen Repositories als Teilprojekt einzubinden, ohne dessen Dateien direkt zu übernehmen. Ein **Submodul** ist ein Git-Repository innerhalb eines anderen Git-Repositories. Es erlaubt, einen festen Commit eines externen Repositories als Teilprojekt einzubinden, ohne dessen Dateien direkt zu übernehmen.
Beispielhafte Struktur: Beispielhafte Struktur:
```plaintext ```plaintext
hauptprojekt/ hauptprojekt/
├── .gitmodules ├── .gitmodules
├── modul1/ ← eingebundenes Submodul ├── modul1/ ← eingebundenes Submodul
└── modul2/ └── modul2/
``` ```
## 🧱 Grundlagen ## 🧱 Grundlagen
### 📌 `.gitmodules` ### 📌 `.gitmodules`
Diese Datei beschreibt Pfad und Remote-URL aller eingebundenen Submodule: Diese Datei beschreibt Pfad und Remote-URL aller eingebundenen Submodule:
```ini ```ini
[submodule "modul1"] [submodule "modul1"]
path = modul1 path = modul1
url = git@github.com:user/modul1.git url = git@github.com:user/modul1.git
``` ```
### 🧠 Merksatz ### 🧠 Merksatz
> Submodule sind **Pointer auf einen bestimmten Commit** eines anderen Repositories. > Submodule sind **Pointer auf einen bestimmten Commit** eines anderen Repositories.
## 🛠️ Submodul hinzufügen ## 🛠️ Submodul hinzufügen
```bash ```bash
git submodule add <repo-url> <zielpfad> git submodule add <repo-url> <zielpfad>
git commit -m "📦 Submodul hinzugefügt" git commit -m "📦 Submodul hinzugefügt"
``` ```
Beispiel: Beispiel:
```bash ```bash
git submodule add git@github.com:user/libmath.git extern/libmath git submodule add git@github.com:user/libmath.git extern/libmath
``` ```
Erzeugt: Erzeugt:
- `.gitmodules` - `.gitmodules`
- Verzeichniseintrag im Git-Index - Verzeichniseintrag im Git-Index
- Initialer Checkout des Submoduls (HEAD auf Remote-Commit) - Initialer Checkout des Submoduls (HEAD auf Remote-Commit)
## 🔄 Submodule aktualisieren ## 🔄 Submodule aktualisieren
```bash ```bash
cd extern/libmath cd extern/libmath
git pull origin main git pull origin main
cd ../.. cd ../..
git add extern/libmath git add extern/libmath
git commit -m "🔄 Submodul libmath aktualisiert" git commit -m "🔄 Submodul libmath aktualisiert"
``` ```
> Nur das **Hauptrepo speichert den Commit-Zeiger**, nicht den Submodul-Inhalt selbst. > Nur das **Hauptrepo speichert den Commit-Zeiger**, nicht den Submodul-Inhalt selbst.
## 📥 Klonen mit Submodulen ## 📥 Klonen mit Submodulen
### Methode 1: Inklusive Submodule ### Methode 1: Inklusive Submodule
```bash ```bash
git clone --recurse-submodules <url> git clone --recurse-submodules <url>
``` ```
### Methode 2: Nachträglich initialisieren ### Methode 2: Nachträglich initialisieren
```bash ```bash
git clone <url> git clone <url>
git submodule update --init git submodule update --init
``` ```
## 🔃 Submodul-Synchronisation ## 🔃 Submodul-Synchronisation
Wenn sich `.gitmodules` ändert (z.B. Remote-URL): Wenn sich `.gitmodules` ändert (z.B. Remote-URL):
```bash ```bash
git submodule sync git submodule sync
``` ```
## 📂 Weitere Remotes im Submodul ## 📂 Weitere Remotes im Submodul
```bash ```bash
cd modul1 cd modul1
git remote add backup git@backup.server:repo.git git remote add backup git@backup.server:repo.git
``` ```
> Diese Remotes sind **lokal**, nicht versioniert. `.gitmodules` kennt nur den Haupt-Remote. > Diese Remotes sind **lokal**, nicht versioniert. `.gitmodules` kennt nur den Haupt-Remote.
## ❗ Stolperfallen und Besonderheiten ## ❗ Stolperfallen und Besonderheiten
| Problem | Erklärung | | Problem | Erklärung |
|--------|-----------| |--------|-----------|
| Submodul wird nicht mitgeclont | `--recurse-submodules` vergessen | | Submodul wird nicht mitgeclont | `--recurse-submodules` vergessen |
| Änderungen im Submodul nicht sichtbar | Submodul-Commit im Hauptrepo nicht geupdated | | Änderungen im Submodul nicht sichtbar | Submodul-Commit im Hauptrepo nicht geupdated |
| `.gitmodules` zeigt nicht funktionierende URL | z.B. lokale URL nach GitHub-Push muss angepasst werden | | `.gitmodules` zeigt nicht funktionierende URL | z.B. lokale URL nach GitHub-Push muss angepasst werden |
| Submodul zeigt „detached HEAD“ | normaler Zustand, wenn Submodul auf festen Commit gesetzt ist | | Submodul zeigt „detached HEAD“ | normaler Zustand, wenn Submodul auf festen Commit gesetzt ist |
## 🔄 Remote-URL wechseln ## 🔄 Remote-URL wechseln
```bash ```bash
# In .gitmodules ändern oder per Befehl: # In .gitmodules ändern oder per Befehl:
git config -f .gitmodules submodule.modul1.url git@github.com:newuser/libmath.git git config -f .gitmodules submodule.modul1.url git@github.com:newuser/libmath.git
git submodule sync git submodule sync
``` ```
## 🚀 Push & Pull Verhalten ## 🚀 Push & Pull Verhalten
| Aktion | Wirkung | | Aktion | Wirkung |
|---------------------|---------| |---------------------|---------|
| `git push` im Hauptrepo | Pusht nur Zeiger auf Submodul-Commit | | `git push` im Hauptrepo | Pusht nur Zeiger auf Submodul-Commit |
| `git push` im Submodul | Muss separat erfolgen | | `git push` im Submodul | Muss separat erfolgen |
| `git pull` im Hauptrepo | Holt *nicht* automatisch neuen Submodul-Stand | | `git pull` im Hauptrepo | Holt *nicht* automatisch neuen Submodul-Stand |
## 🧼 Submodul löschen ## 🧼 Submodul löschen
```bash ```bash
# Schritt 1: Entfernen # Schritt 1: Entfernen
git submodule deinit -f pfad/zum/modul git submodule deinit -f pfad/zum/modul
git rm -f pfad/zum/modul git rm -f pfad/zum/modul
rm -rf .git/modules/pfad/zum/modul rm -rf .git/modules/pfad/zum/modul
git commit -m "❌ Submodul entfernt" git commit -m "❌ Submodul entfernt"
``` ```
## 🧰 Best Practices ## 🧰 Best Practices
- **Nur stabile Submodul-Commits einchecken**, keine laufenden Branches. - **Nur stabile Submodul-Commits einchecken**, keine laufenden Branches.
- **Submodule niemals blind aktualisieren** Änderungen genau prüfen. - **Submodule niemals blind aktualisieren** Änderungen genau prüfen.
- **Remote-Umschaltung dokumentieren oder automatisieren**, z.B. per Script. - **Remote-Umschaltung dokumentieren oder automatisieren**, z.B. per Script.
- **Submodule klein halten** große, tief verschachtelte Strukturen vermeiden. - **Submodule klein halten** große, tief verschachtelte Strukturen vermeiden.
- Für wiederverwendbare Bibliotheken oder Assets ideal (CAD, Snippets, Markdown, etc.). - Für wiederverwendbare Bibliotheken oder Assets ideal (CAD, Snippets, Markdown, etc.).
## 📎 Nützliche Kommandos ## 📎 Nützliche Kommandos
```bash ```bash
git submodule status # Überblick über alle Submodule git submodule status # Überblick über alle Submodule
git submodule update --init # Submodule initial holen git submodule update --init # Submodule initial holen
git submodule update --remote # Auf neuesten Remote-Stand updaten git submodule update --remote # Auf neuesten Remote-Stand updaten
git config -f .gitmodules ... # .gitmodules direkt bearbeiten git config -f .gitmodules ... # .gitmodules direkt bearbeiten
``` ```
## 📑 Beispiel `.gitmodules` mit kommentierter Remote-Auswahl ## 📑 Beispiel `.gitmodules` mit kommentierter Remote-Auswahl
```ini ```ini
[submodule "modul1"] [submodule "modul1"]
path = modul1 path = modul1
url = ssh://git@local.example.com:2222/myorg/modul1.git url = ssh://git@local.example.com:2222/myorg/modul1.git
# url = git@github.com:myorg/modul1.git # url = git@github.com:myorg/modul1.git
``` ```
## 🧭 Alternative: Subtree statt Submodul? ## 🧭 Alternative: Subtree statt Submodul?
Subtree ist einfacher zu verwalten, aber: Subtree ist einfacher zu verwalten, aber:
- kein fester Commit-Zeiger, - kein fester Commit-Zeiger,
- kein Remote-Wechsel ohne Umweg, - kein Remote-Wechsel ohne Umweg,
- gemergte Historie im Hauptrepo. - gemergte Historie im Hauptrepo.
**Submodul = getrennte Repos** **Submodul = getrennte Repos**
**Subtree = eingemergter Inhalt** **Subtree = eingemergter Inhalt**
## 📚 Fazit ## 📚 Fazit
Git-Submodule sind mächtig, aber erfordern **Disziplin und Überblick**. Für wiederverwendbare Komponenten, zentral gepflegte Inhalte oder externe Bibliotheken sind sie oft die bessere Wahl als Duplikate oder Copy-Paste. Git-Submodule sind mächtig, aber erfordern **Disziplin und Überblick**. Für wiederverwendbare Komponenten, zentral gepflegte Inhalte oder externe Bibliotheken sind sie oft die bessere Wahl als Duplikate oder Copy-Paste.
## 🔗 Weiterführende Links ## 🔗 Weiterführende Links
- [Git Book: Submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) - [Git Book: Submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules)
- [git-scm Doku: submodule](https://git-scm.com/docs/git-submodule) - [git-scm Doku: submodule](https://git-scm.com/docs/git-submodule)
- [Vergleich Submodule vs. Subtree](https://www.atlassian.com/git/tutorials/git-submodule) - [Vergleich Submodule vs. Subtree](https://www.atlassian.com/git/tutorials/git-submodule)

View File

@ -1,4 +1,4 @@
# Artikel: git # Artikel: git
- [SSH-Zugriff auf Git-Repository in WSL einrichten](git-ssh-remote.md) - [SSH-Zugriff auf Git-Repository in WSL einrichten](git-ssh-remote.md)
- [Git Remote-Branches: Häufige Aufgaben und Lösungen](git-remote-branch.md) - [Git Remote-Branches: Häufige Aufgaben und Lösungen](git-remote-branch.md)

View File

@ -1,182 +1,182 @@
# Helix Editor Ein umfassender Einstieg für Anfänger (Deutsch) # Helix Editor Ein umfassender Einstieg für Anfänger (Deutsch)
## Inhalt ## Inhalt
- [Helix Editor Ein umfassender Einstieg für Anfänger (Deutsch)](#helix-editor--ein-umfassender-einstieg-für-anfänger-deutsch) - [Helix Editor Ein umfassender Einstieg für Anfänger (Deutsch)](#helix-editor--ein-umfassender-einstieg-für-anfänger-deutsch)
- [Inhalt](#inhalt) - [Inhalt](#inhalt)
- [✨ Was ist Helix?](#-was-ist-helix) - [✨ Was ist Helix?](#-was-ist-helix)
- [🔧 Installation](#-installation) - [🔧 Installation](#-installation)
- [Linux (Fedora, Arch, Debian)](#linux-fedora-arch-debian) - [Linux (Fedora, Arch, Debian)](#linux-fedora-arch-debian)
- [GitHub Release (empfohlen für aktuellste Version)](#github-release-empfohlen-für-aktuellste-version) - [GitHub Release (empfohlen für aktuellste Version)](#github-release-empfohlen-für-aktuellste-version)
- [📁 Erstes Projekt starten](#-erstes-projekt-starten) - [📁 Erstes Projekt starten](#-erstes-projekt-starten)
- [Beispiel: Rust-Projekt](#beispiel-rust-projekt) - [Beispiel: Rust-Projekt](#beispiel-rust-projekt)
- [Beispiel: JavaScript-Projekt](#beispiel-javascript-projekt) - [Beispiel: JavaScript-Projekt](#beispiel-javascript-projekt)
- [⌨ Bedienkonzept von Helix](#-bedienkonzept-von-helix) - [⌨ Bedienkonzept von Helix](#-bedienkonzept-von-helix)
- [Modale Steuerung (ähnlich wie Vim)](#modale-steuerung-ähnlich-wie-vim) - [Modale Steuerung (ähnlich wie Vim)](#modale-steuerung-ähnlich-wie-vim)
- [Wechsel der Modi](#wechsel-der-modi) - [Wechsel der Modi](#wechsel-der-modi)
- [⚖️ Wichtige Tastenkombinationen](#-wichtige-tastenkombinationen) - [⚖️ Wichtige Tastenkombinationen](#-wichtige-tastenkombinationen)
- [🪨 Sprachserver (LSP)](#-sprachserver-lsp) - [🪨 Sprachserver (LSP)](#-sprachserver-lsp)
- [Rust](#rust) - [Rust](#rust)
- [JavaScript/TypeScript](#javascripttypescript) - [JavaScript/TypeScript](#javascripttypescript)
- [C / C++](#c--c) - [C / C++](#c--c)
- [⚖️ LSP-Befehle in Helix](#-lsp-befehle-in-helix) - [⚖️ LSP-Befehle in Helix](#-lsp-befehle-in-helix)
- [📂 Konfiguration](#-konfiguration) - [📂 Konfiguration](#-konfiguration)
- [Beispiel-Inhalt](#beispiel-inhalt) - [Beispiel-Inhalt](#beispiel-inhalt)
- [🌍 Weitere Ressourcen](#-weitere-ressourcen) - [🌍 Weitere Ressourcen](#-weitere-ressourcen)
## ✨ Was ist Helix? ## ✨ Was ist Helix?
Helix ist ein moderner, terminalbasierter Code-Editor mit Fokus auf Produktivität, Effizienz und minimalistische Bedienung. Er verwendet **modale Eingabe** (wie Vim), bietet jedoch eine eigene, einsteigerfreundlichere Philosophie mit moderner Technologie wie **LSP**, **Tree-sitter**, und Syntax-Highlighting direkt aus dem Terminal. Helix ist ein moderner, terminalbasierter Code-Editor mit Fokus auf Produktivität, Effizienz und minimalistische Bedienung. Er verwendet **modale Eingabe** (wie Vim), bietet jedoch eine eigene, einsteigerfreundlichere Philosophie mit moderner Technologie wie **LSP**, **Tree-sitter**, und Syntax-Highlighting direkt aus dem Terminal.
--- ---
## 🔧 Installation ## 🔧 Installation
### Linux (Fedora, Arch, Debian) ### Linux (Fedora, Arch, Debian)
```bash ```bash
# Fedora # Fedora
sudo dnf install helix sudo dnf install helix
# Arch (via pacman) # Arch (via pacman)
sudo pacman -S helix sudo pacman -S helix
# Debian/Ubuntu (nur in neueren Versionen oder via GitHub) # Debian/Ubuntu (nur in neueren Versionen oder via GitHub)
``` ```
### GitHub Release (empfohlen für aktuellste Version) ### GitHub Release (empfohlen für aktuellste Version)
1. Gehe zu: [https://github.com/helix-editor/helix/releases](https://github.com/helix-editor/helix/releases) 1. Gehe zu: [https://github.com/helix-editor/helix/releases](https://github.com/helix-editor/helix/releases)
2. Lade das passende Paket für dein System herunter 2. Lade das passende Paket für dein System herunter
3. Entpacken: 3. Entpacken:
```bash ```bash
tar -xvf helix-*-x86_64-linux.tar.xz tar -xvf helix-*-x86_64-linux.tar.xz
sudo cp helix-*/helix/hx /usr/local/bin/ sudo cp helix-*/helix/hx /usr/local/bin/
``` ```
--- ---
## 📁 Erstes Projekt starten ## 📁 Erstes Projekt starten
### Beispiel: Rust-Projekt ### Beispiel: Rust-Projekt
```bash ```bash
cargo new hallo_helix cargo new hallo_helix
cd hallo_helix cd hallo_helix
hx src/main.rs hx src/main.rs
``` ```
### Beispiel: JavaScript-Projekt ### Beispiel: JavaScript-Projekt
```bash ```bash
mkdir node_hello && cd node_hello mkdir node_hello && cd node_hello
echo 'console.log("Hallo, Welt!");' > index.js echo 'console.log("Hallo, Welt!");' > index.js
hx index.js hx index.js
``` ```
--- ---
## ⌨ Bedienkonzept von Helix ## ⌨ Bedienkonzept von Helix
### Modale Steuerung (ähnlich wie Vim) ### Modale Steuerung (ähnlich wie Vim)
- **Normalmodus**: Standardmodus zum Navigieren und Bearbeiten - **Normalmodus**: Standardmodus zum Navigieren und Bearbeiten
- **Einfügemodus (Insert)**: `i` drücken zum Schreiben - **Einfügemodus (Insert)**: `i` drücken zum Schreiben
- **Auswahlmodus (Select)**: `v` für Zeichenweise, `V` für Zeilenweise Auswahl - **Auswahlmodus (Select)**: `v` für Zeichenweise, `V` für Zeilenweise Auswahl
### Wechsel der Modi ### Wechsel der Modi
| Modus | Taste | Funktion | | Modus | Taste | Funktion |
| ----------- | ----- | ----------------------- | | ----------- | ----- | ----------------------- |
| Normal | `Esc` | Zur Steuerung & Befehle | | Normal | `Esc` | Zur Steuerung & Befehle |
| Insert | `i` | Einfügen / Tippen | | Insert | `i` | Einfügen / Tippen |
| Select | `v` | Auswahl ab Cursor | | Select | `v` | Auswahl ab Cursor |
| Line-Select | `V` | Ganze Zeile auswählen | | Line-Select | `V` | Ganze Zeile auswählen |
--- ---
## ⚖️ Wichtige Tastenkombinationen ## ⚖️ Wichtige Tastenkombinationen
| Tastenkombi | Bedeutung | | Tastenkombi | Bedeutung |
| ----------- | --------------------------------- | | ----------- | --------------------------------- |
| `:w` | Datei speichern | | `:w` | Datei speichern |
| `:q` | Editor beenden | | `:q` | Editor beenden |
| `:wq` | Speichern und beenden | | `:wq` | Speichern und beenden |
| `g g` | Zum Anfang der Datei | | `g g` | Zum Anfang der Datei |
| `G` | Zum Ende der Datei | | `G` | Zum Ende der Datei |
| `d d` | Aktuelle Zeile löschen | | `d d` | Aktuelle Zeile löschen |
| `u` | Letzte Änderung rückgängig machen | | `u` | Letzte Änderung rückgängig machen |
| `space + /` | Fuzzy-Dateisuche starten | | `space + /` | Fuzzy-Dateisuche starten |
| `space + g` | Git-Diff anzeigen | | `space + g` | Git-Diff anzeigen |
--- ---
## 🪨 Sprachserver (LSP) ## 🪨 Sprachserver (LSP)
Helix erkennt automatisch den Dateityp und startet den passenden Sprachserver: Helix erkennt automatisch den Dateityp und startet den passenden Sprachserver:
### Rust ### Rust
```bash ```bash
rustup component add rust-analyzer rustup component add rust-analyzer
``` ```
### JavaScript/TypeScript ### JavaScript/TypeScript
```bash ```bash
npm install -g typescript typescript-language-server npm install -g typescript typescript-language-server
``` ```
### C / C++ ### C / C++
```bash ```bash
sudo dnf install clang clang-tools-extra sudo dnf install clang clang-tools-extra
``` ```
--- ---
## ⚖️ LSP-Befehle in Helix ## ⚖️ LSP-Befehle in Helix
| Taste | Bedeutung | | Taste | Bedeutung |
| ----- | ------------------------------- | | ----- | ------------------------------- |
| `g d` | Gehe zur Definition | | `g d` | Gehe zur Definition |
| `g r` | Gehe zu Referenzen | | `g r` | Gehe zu Referenzen |
| `K` | Hover-Info anzeigen (Typ, Doku) | | `K` | Hover-Info anzeigen (Typ, Doku) |
| `=` | Formatieren | | `=` | Formatieren |
--- ---
## 📂 Konfiguration ## 📂 Konfiguration
Helix-Konfiguration liegt unter: Helix-Konfiguration liegt unter:
```bash ```bash
~/.config/helix/config.toml ~/.config/helix/config.toml
``` ```
Zum Öffnen: Zum Öffnen:
```bash ```bash
:config-open :config-open
``` ```
### Beispiel-Inhalt ### Beispiel-Inhalt
```toml ```toml
theme = "base16_default_dark" theme = "base16_default_dark"
[keys.normal] [keys.normal]
"C-s" = ":w" "C-s" = ":w"
"C-q" = ":wq" "C-q" = ":wq"
``` ```
--- ---
## 🌍 Weitere Ressourcen ## 🌍 Weitere Ressourcen
- Offizielle Seite: [https://helix-editor.com](https://helix-editor.com) - Offizielle Seite: [https://helix-editor.com](https://helix-editor.com)
- GitHub: [https://github.com/helix-editor/helix](https://github.com/helix-editor/helix) - GitHub: [https://github.com/helix-editor/helix](https://github.com/helix-editor/helix)
- Tastenkombis: [https://docs.helix-editor.com/](https://docs.helix-editor.com/) - Tastenkombis: [https://docs.helix-editor.com/](https://docs.helix-editor.com/)
--- ---

View File

@ -1,345 +1,345 @@
# Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration # Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration
## ✨ Ziel dieses Dokuments ## ✨ Ziel dieses Dokuments
Diese Anleitung richtet sich an Anfänger, die lernen wollen, wann sie welchen JavaScript-Dialekt (CommonJS vs. ESM) verwenden sollten, wie sie TypeScript korrekt konfigurieren und worauf sie bei modernen Projekten achten müssen. Diese Anleitung richtet sich an Anfänger, die lernen wollen, wann sie welchen JavaScript-Dialekt (CommonJS vs. ESM) verwenden sollten, wie sie TypeScript korrekt konfigurieren und worauf sie bei modernen Projekten achten müssen.
## Inhalt ## Inhalt
- [Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration](#einstieg-in-javascript-dialekte-und-typescript-konfiguration) - [Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration](#einstieg-in-javascript-dialekte-und-typescript-konfiguration)
- [✨ Ziel dieses Dokuments](#-ziel-dieses-dokuments) - [✨ Ziel dieses Dokuments](#-ziel-dieses-dokuments)
- [Inhalt](#inhalt) - [Inhalt](#inhalt)
- [🔢 Begriffe erklärt](#-begriffe-erklärt) - [🔢 Begriffe erklärt](#-begriffe-erklärt)
- [JavaScript-Dialekte (Modulsysteme)](#javascript-dialekte-modulsysteme) - [JavaScript-Dialekte (Modulsysteme)](#javascript-dialekte-modulsysteme)
- [Was ist TypeScript?](#was-ist-typescript) - [Was ist TypeScript?](#was-ist-typescript)
- [🔍 Wann verwende ich was?](#-wann-verwende-ich-was) - [🔍 Wann verwende ich was?](#-wann-verwende-ich-was)
- [🔧 TypeScript richtig konfigurieren](#-typescript-richtig-konfigurieren) - [🔧 TypeScript richtig konfigurieren](#-typescript-richtig-konfigurieren)
- [📦 Was ist ESM?](#-was-ist-esm) - [📦 Was ist ESM?](#-was-ist-esm)
- [✅ Wann kann/sollte/muss man **ESM** verwenden?](#-wann-kannsolltemuss-man-esm-verwenden) - [✅ Wann kann/sollte/muss man **ESM** verwenden?](#-wann-kannsolltemuss-man-esm-verwenden)
- [🟢 **Du kannst ESM verwenden**, wenn](#-du-kannst-esm-verwenden-wenn) - [🟢 **Du kannst ESM verwenden**, wenn](#-du-kannst-esm-verwenden-wenn)
- [🟡 **Du solltest ESM verwenden**, wenn](#-du-solltest-esm-verwenden-wenn) - [🟡 **Du solltest ESM verwenden**, wenn](#-du-solltest-esm-verwenden-wenn)
- [🔴 **Du musst ESM verwenden**, wenn](#-du-musst-esm-verwenden-wenn) - [🔴 **Du musst ESM verwenden**, wenn](#-du-musst-esm-verwenden-wenn)
- [⚙️ TypeScript-Konfiguration für ESM](#-typescript-konfiguration-für-esm) - [⚙️ TypeScript-Konfiguration für ESM](#-typescript-konfiguration-für-esm)
- [📌 Merkmale von ESM](#-merkmale-von-esm) - [📌 Merkmale von ESM](#-merkmale-von-esm)
- [⚠️ Besonderheiten und Stolperfallen](#-besonderheiten-und-stolperfallen) - [⚠️ Besonderheiten und Stolperfallen](#-besonderheiten-und-stolperfallen)
- [✅ Fazit ESM](#-fazit-esm) - [✅ Fazit ESM](#-fazit-esm)
- [🌐 CommonJS-Konfiguration CJS (Alternative)](#-commonjs-konfiguration-cjs-alternative) - [🌐 CommonJS-Konfiguration CJS (Alternative)](#-commonjs-konfiguration-cjs-alternative)
- [📦 Was ist CommonJS?](#-was-ist-commonjs) - [📦 Was ist CommonJS?](#-was-ist-commonjs)
- [✅ Wann kann/sollte/muss man **CommonJS** verwenden?](#-wann-kannsolltemuss-man-commonjs-verwenden) - [✅ Wann kann/sollte/muss man **CommonJS** verwenden?](#-wann-kannsolltemuss-man-commonjs-verwenden)
- [🟢 **Du kannst CJS verwenden**, wenn](#-du-kannst-cjs-verwenden-wenn) - [🟢 **Du kannst CJS verwenden**, wenn](#-du-kannst-cjs-verwenden-wenn)
- [🟡 **Du solltest CJS verwenden**, wenn](#-du-solltest-cjs-verwenden-wenn) - [🟡 **Du solltest CJS verwenden**, wenn](#-du-solltest-cjs-verwenden-wenn)
- [🔴 **Du musst CJS verwenden**, wenn](#-du-musst-cjs-verwenden-wenn) - [🔴 **Du musst CJS verwenden**, wenn](#-du-musst-cjs-verwenden-wenn)
- [⚙️ TypeScript-Konfiguration für CJS](#-typescript-konfiguration-für-cjs) - [⚙️ TypeScript-Konfiguration für CJS](#-typescript-konfiguration-für-cjs)
- [📌 Merkmale von CommonJS](#-merkmale-von-commonjs) - [📌 Merkmale von CommonJS](#-merkmale-von-commonjs)
- [✅ Fazit CommonJS](#-fazit-commonjs) - [✅ Fazit CommonJS](#-fazit-commonjs)
- [📄 Fazit: Empfehlungen](#-fazit-empfehlungen) - [📄 Fazit: Empfehlungen](#-fazit-empfehlungen)
- [📁 Dateiendungen in Node.js](#-dateiendungen-in-nodejs) - [📁 Dateiendungen in Node.js](#-dateiendungen-in-nodejs)
- [⚠️ Typische Fehler vermeiden](#-typische-fehler-vermeiden) - [⚠️ Typische Fehler vermeiden](#-typische-fehler-vermeiden)
- [🚀 CLI-Build-Tipps (tsc)](#-cli-build-tipps-tsc) - [🚀 CLI-Build-Tipps (tsc)](#-cli-build-tipps-tsc)
- [📍 Weiterführende Themen](#-weiterführende-themen) - [📍 Weiterführende Themen](#-weiterführende-themen)
--- ---
## 🔢 Begriffe erklärt ## 🔢 Begriffe erklärt
### JavaScript-Dialekte (Modulsysteme) ### JavaScript-Dialekte (Modulsysteme)
| Name | Kürzel | Typ | Verwendung heute | | Name | Kürzel | Typ | Verwendung heute |
| ------------------ | ------ | ----------- | ----------------------- | | ------------------ | ------ | ----------- | ----------------------- |
| CommonJS | CJS | `require()` | Ältere Node.js-Projekte | | CommonJS | CJS | `require()` | Ältere Node.js-Projekte |
| ECMAScript Modules | ESM | `import` | Browser, moderne Tools | | ECMAScript Modules | ESM | `import` | Browser, moderne Tools |
- **CommonJS:** Nutzt `require()` und `module.exports`. Standard bis Node 12. - **CommonJS:** Nutzt `require()` und `module.exports`. Standard bis Node 12.
- **ESM:** Nutzt `import`/`export`. Standard im Browser und in Node ab Version 14+. - **ESM:** Nutzt `import`/`export`. Standard im Browser und in Node ab Version 14+.
### Was ist TypeScript? ### Was ist TypeScript?
TypeScript ist eine statisch typisierte Obermenge von JavaScript, die zu normalem JS kompiliert wird. TypeScript ist eine statisch typisierte Obermenge von JavaScript, die zu normalem JS kompiliert wird.
--- ---
## 🔍 Wann verwende ich was? ## 🔍 Wann verwende ich was?
| Ziel | Modulformat | Empfehlung | Grund | | Ziel | Modulformat | Empfehlung | Grund |
| -------------------------- | ------------ | -------------- | ------------------------------------------ | | -------------------------- | ------------ | -------------- | ------------------------------------------ |
| 📅 Moderne Webanwendung | ESM | Ja | Browser erwartet ESM | | 📅 Moderne Webanwendung | ESM | Ja | Browser erwartet ESM |
| 📄 Node.js CLI-Tool | ESM oder CJS | Beides möglich | ESM zukunftssicher, CJS maximal kompatibel | | 📄 Node.js CLI-Tool | ESM oder CJS | Beides möglich | ESM zukunftssicher, CJS maximal kompatibel |
| 🔐 Legacy-Node-Integration | CJS | Ja | Viele NPM-Pakete sind CJS-only | | 🔐 Legacy-Node-Integration | CJS | Ja | Viele NPM-Pakete sind CJS-only |
| 🔌 Electron Renderer | ESM | Ja (Pflicht) | Chromium-only, kein CJS | | 🔌 Electron Renderer | ESM | Ja (Pflicht) | Chromium-only, kein CJS |
| 🔁 Vite/Webpack-Projekt | ESM | Ja | Toolchain basiert auf ESM | | 🔁 Vite/Webpack-Projekt | ESM | Ja | Toolchain basiert auf ESM |
--- ---
## 🔧 TypeScript richtig konfigurieren ## 🔧 TypeScript richtig konfigurieren
Eine vollständige Zusammenfassung zu **ESM (ECMAScript Modules)** wann du es **verwenden kannst**, **solltest** oder **musst**, sowie alle wesentlichen technischen Eigenschaften. Stil und Umfang entsprechen exakt der vorherigen CommonJS-Zusammenfassung. Eine vollständige Zusammenfassung zu **ESM (ECMAScript Modules)** wann du es **verwenden kannst**, **solltest** oder **musst**, sowie alle wesentlichen technischen Eigenschaften. Stil und Umfang entsprechen exakt der vorherigen CommonJS-Zusammenfassung.
--- ---
### 📦 Was ist ESM? ### 📦 Was ist ESM?
**ESM (ECMAScript Modules)** ist das moderne Modulsystem von JavaScript: **ESM (ECMAScript Modules)** ist das moderne Modulsystem von JavaScript:
- verwendet `import`/`export`-Syntax - verwendet `import`/`export`-Syntax
- wird nativ von allen modernen Browsern und Node.js (ab v14+) unterstützt - wird nativ von allen modernen Browsern und Node.js (ab v14+) unterstützt
- ist Standard in allen modernen JS-Toolchains (Vite, Webpack, esbuild, etc.) - ist Standard in allen modernen JS-Toolchains (Vite, Webpack, esbuild, etc.)
```js ```js
// ESM-Stil // ESM-Stil
import fs from 'node:fs/promises'; import fs from 'node:fs/promises';
export function read(path) { export function read(path) {
return fs.readFile(path, 'utf-8'); return fs.readFile(path, 'utf-8');
} }
``` ```
--- ---
### ✅ Wann kann/sollte/muss man **ESM** verwenden? ### ✅ Wann kann/sollte/muss man **ESM** verwenden?
#### 🟢 **Du kannst ESM verwenden**, wenn #### 🟢 **Du kannst ESM verwenden**, wenn
- du mit **modernen Node.js-Versionen (v16+)** arbeitest - du mit **modernen Node.js-Versionen (v16+)** arbeitest
- du ein **Frontend-Tool** oder ein **Browser-kompatibles Projekt** baust - du ein **Frontend-Tool** oder ein **Browser-kompatibles Projekt** baust
- du Tree-Shaking oder Dynamic `import()` nutzen willst - du Tree-Shaking oder Dynamic `import()` nutzen willst
- du Typkonsistenz mit dem Browser willst (gleiche Syntax wie dort) - du Typkonsistenz mit dem Browser willst (gleiche Syntax wie dort)
#### 🟡 **Du solltest ESM verwenden**, wenn #### 🟡 **Du solltest ESM verwenden**, wenn
| Situation | Grund | | Situation | Grund |
| ------------------------------------------------------------------- | ---------------------------- | | ------------------------------------------------------------------- | ---------------------------- |
| 🌐 Du entwickelst Webanwendungen mit Vite, Nuxt, Webpack o. ä. | Diese Tools basieren auf ESM | | 🌐 Du entwickelst Webanwendungen mit Vite, Nuxt, Webpack o. ä. | Diese Tools basieren auf ESM |
| 💡 Du möchtest moderne Syntax und Tooling nutzen | ESM ist Standard | | 💡 Du möchtest moderne Syntax und Tooling nutzen | ESM ist Standard |
| 🔄 Du willst `import()` dynamisch verwenden | Nur in ESM verfügbar | | 🔄 Du willst `import()` dynamisch verwenden | Nur in ESM verfügbar |
| 📚 Du schreibst eine wiederverwendbare Bibliothek für neue Projekte | Zukunftssicherheit | | 📚 Du schreibst eine wiederverwendbare Bibliothek für neue Projekte | Zukunftssicherheit |
| 🧩 Du verwendest Deno, Bun oder moderne Plattformen | ESM only | | 🧩 Du verwendest Deno, Bun oder moderne Plattformen | ESM only |
#### 🔴 **Du musst ESM verwenden**, wenn #### 🔴 **Du musst ESM verwenden**, wenn
- du im **Browser** arbeitest (ohne Bundler) → dort ist `import` Pflicht - du im **Browser** arbeitest (ohne Bundler) → dort ist `import` Pflicht
- du in **Electron-Renderer-Prozessen** arbeitest - du in **Electron-Renderer-Prozessen** arbeitest
- du ein Projekt hast mit `"type": "module"` und `.js`-Dateien → dann interpretiert Node sie nur als ESM - du ein Projekt hast mit `"type": "module"` und `.js`-Dateien → dann interpretiert Node sie nur als ESM
- du ESM-only-Dependencies nutzt (z.B. `chalk@5`, `node-fetch@3`) - du ESM-only-Dependencies nutzt (z.B. `chalk@5`, `node-fetch@3`)
--- ---
### ⚙️ TypeScript-Konfiguration für ESM ### ⚙️ TypeScript-Konfiguration für ESM
```jsonc ```jsonc
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES2020", "target": "ES2020",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "node",
"outDir": "./dist", "outDir": "./dist",
"rootDir": "./src", "rootDir": "./src",
"strict": true, "strict": true,
"esModuleInterop": true, "esModuleInterop": true,
"allowSyntheticDefaultImports": true "allowSyntheticDefaultImports": true
} }
} }
``` ```
Und in der `package.json`: Und in der `package.json`:
```json ```json
{ {
"type": "module" "type": "module"
} }
``` ```
**Wichtig:** Ohne `"type": "module"` behandelt Node deine `.js`-Dateien **nicht als ESM**, sondern als CommonJS. **Wichtig:** Ohne `"type": "module"` behandelt Node deine `.js`-Dateien **nicht als ESM**, sondern als CommonJS.
--- ---
### 📌 Merkmale von ESM ### 📌 Merkmale von ESM
| Merkmal | ESM | | Merkmal | ESM |
| ------------------------- | -------------------------------------------- | | ------------------------- | -------------------------------------------- |
| Import-Syntax | `import`, `export` | | Import-Syntax | `import`, `export` |
| Export-Syntax | `export default`, `export {...}` | | Export-Syntax | `export default`, `export {...}` |
| Dateiendung `.js` | **.js** nur mit `"type": "module"` | | Dateiendung `.js` | **.js** nur mit `"type": "module"` |
| `.mjs` | explizit ESM | | `.mjs` | explizit ESM |
| `__dirname`, `__filename` | ❌ nicht vorhanden, nur via `import.meta.url` | | `__dirname`, `__filename` | ❌ nicht vorhanden, nur via `import.meta.url` |
| Dynamische Imports | ✅ `await import('...')` | | Dynamische Imports | ✅ `await import('...')` |
| Tree Shaking | ✅ möglich | | Tree Shaking | ✅ möglich |
| Browser-kompatibel | ✅ nativ | | Browser-kompatibel | ✅ nativ |
| CommonJS-Interop | ❗ mit Einschränkungen (`createRequire`) | | CommonJS-Interop | ❗ mit Einschränkungen (`createRequire`) |
--- ---
### ⚠️ Besonderheiten und Stolperfallen ### ⚠️ Besonderheiten und Stolperfallen
| Problem | Lösung | | Problem | Lösung |
| --------------------------------------------- | ------------------------------------------- | | --------------------------------------------- | ------------------------------------------- |
| ❌ `__dirname`/`__filename` fehlen | nutze `import.meta.url` + `fileURLToPath()` | | ❌ `__dirname`/`__filename` fehlen | nutze `import.meta.url` + `fileURLToPath()` |
| ❌ `require()` nicht verfügbar | verwende `import`, oder `createRequire()` | | ❌ `require()` nicht verfügbar | verwende `import`, oder `createRequire()` |
| ❌ `.js` muss beim Import angegeben werden | z.B. `import './utils.js'` | | ❌ `.js` muss beim Import angegeben werden | z.B. `import './utils.js'` |
| ❌ viele alte Pakete sind nicht ESM-kompatibel | ggf. CommonJS verwenden | | ❌ viele alte Pakete sind nicht ESM-kompatibel | ggf. CommonJS verwenden |
--- ---
### ✅ Fazit ESM ### ✅ Fazit ESM
> **ESM ist der offizielle Standard für moderne JavaScript-Entwicklung** sowohl im Browser als auch in modernen Node.js-Umgebungen. > **ESM ist der offizielle Standard für moderne JavaScript-Entwicklung** sowohl im Browser als auch in modernen Node.js-Umgebungen.
Du solltest ESM verwenden, wenn du: Du solltest ESM verwenden, wenn du:
- neue Projekte startest, - neue Projekte startest,
- moderne Toolchains nutzt, - moderne Toolchains nutzt,
- oder langfristige Kompatibilität willst. - oder langfristige Kompatibilität willst.
In Zweifelsfällen gilt: **Wenn du mit aktuellen Tools und Node-Versionen arbeitest, nimm ESM.** In Zweifelsfällen gilt: **Wenn du mit aktuellen Tools und Node-Versionen arbeitest, nimm ESM.**
Nur bei Problemen mit alten Paketen oder Tooling solltest du temporär auf CommonJS zurückfallen. Nur bei Problemen mit alten Paketen oder Tooling solltest du temporär auf CommonJS zurückfallen.
--- ---
## 🌐 CommonJS-Konfiguration CJS (Alternative) ## 🌐 CommonJS-Konfiguration CJS (Alternative)
### 📦 Was ist CommonJS? ### 📦 Was ist CommonJS?
**CommonJS (CJS)** ist das ursprüngliche Modulsystem von Node.js: **CommonJS (CJS)** ist das ursprüngliche Modulsystem von Node.js:
- verwendet `require()` zum Importieren - verwendet `require()` zum Importieren
- verwendet `module.exports` oder `exports` zum Exportieren - verwendet `module.exports` oder `exports` zum Exportieren
- keine native Unterstützung für `import`/`export` - keine native Unterstützung für `import`/`export`
- funktioniert nur in Node.js (nicht im Browser ohne Bundler) - funktioniert nur in Node.js (nicht im Browser ohne Bundler)
```js ```js
// CommonJS-Stil // CommonJS-Stil
const fs = require('fs'); const fs = require('fs');
module.exports = { read: fs.readFileSync }; module.exports = { read: fs.readFileSync };
``` ```
--- ---
### ✅ Wann kann/sollte/muss man **CommonJS** verwenden? ### ✅ Wann kann/sollte/muss man **CommonJS** verwenden?
#### 🟢 **Du kannst CJS verwenden**, wenn #### 🟢 **Du kannst CJS verwenden**, wenn
- du ein CLI-Tool oder Node.js-Skript erstellst - du ein CLI-Tool oder Node.js-Skript erstellst
- du maximale **Kompatibilität** ohne ESM-Komplikationen willst - du maximale **Kompatibilität** ohne ESM-Komplikationen willst
- du keine modernen ESM-Features brauchst - du keine modernen ESM-Features brauchst
- du auf Build-Tools verzichtest und direkt `.js`-Dateien startest - du auf Build-Tools verzichtest und direkt `.js`-Dateien startest
#### 🟡 **Du solltest CJS verwenden**, wenn #### 🟡 **Du solltest CJS verwenden**, wenn
| Situation | Grund | | Situation | Grund |
| ------------------------------------------------------------------- | ------------------------------------------------------ | | ------------------------------------------------------------------- | ------------------------------------------------------ |
| 🔄 Du arbeitest mit älteren Node.js-Versionen (z.B. v12 oder v10) | ESM ist dort nicht stabil | | 🔄 Du arbeitest mit älteren Node.js-Versionen (z.B. v12 oder v10) | ESM ist dort nicht stabil |
| 📦 Du nutzt NPM-Pakete, die **kein ESM unterstützen** | `require()` wird erwartet | | 📦 Du nutzt NPM-Pakete, die **kein ESM unterstützen** | `require()` wird erwartet |
| 🧪 Du verwendest alte Tools, Tests oder Konfigurationen | z.B. alte `mocha`, `gulpfile.js`, `webpack.config.js` | | 🧪 Du verwendest alte Tools, Tests oder Konfigurationen | z.B. alte `mocha`, `gulpfile.js`, `webpack.config.js` |
| 🧱 Du brauchst direkten Zugriff auf `__dirname`, `__filename` | Diese fehlen in ESM | | 🧱 Du brauchst direkten Zugriff auf `__dirname`, `__filename` | Diese fehlen in ESM |
| 📜 Du möchtest `.js`-Dateien ohne `.mjs` oder `type: module` nutzen | CommonJS macht keine Vorgaben für Dateiendungen | | 📜 Du möchtest `.js`-Dateien ohne `.mjs` oder `type: module` nutzen | CommonJS macht keine Vorgaben für Dateiendungen |
#### 🔴 **Du musst CJS verwenden**, wenn #### 🔴 **Du musst CJS verwenden**, wenn
- das Node.js-Modul, das du importieren willst, **nur `module.exports` exportiert** (kein ESM-Support) - das Node.js-Modul, das du importieren willst, **nur `module.exports` exportiert** (kein ESM-Support)
- dein Projekt oder Tool **nicht mit ESM kompatibel ist** (ältere Tooling oder NPM-Module) - dein Projekt oder Tool **nicht mit ESM kompatibel ist** (ältere Tooling oder NPM-Module)
- du `require()` oder dynamisches Laden (`require(dynamicPath)`) verwendest, was in ESM nicht geht - du `require()` oder dynamisches Laden (`require(dynamicPath)`) verwendest, was in ESM nicht geht
--- ---
### ⚙️ TypeScript-Konfiguration für CJS ### ⚙️ TypeScript-Konfiguration für CJS
```jsonc ```jsonc
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES2020", "target": "ES2020",
"module": "CommonJS", "module": "CommonJS",
"outDir": "./dist", "outDir": "./dist",
"rootDir": "./src", "rootDir": "./src",
"strict": true, "strict": true,
"esModuleInterop": true "esModuleInterop": true
} }
} }
``` ```
Und in der `package.json`: Und in der `package.json`:
```json ```json
{ {
"type": "commonjs" "type": "commonjs"
} }
``` ```
**Hinweis:** Das `"type"`-Feld ist für Node wichtig, nicht für TypeScript. **Hinweis:** Das `"type"`-Feld ist für Node wichtig, nicht für TypeScript.
--- ---
### 📌 Merkmale von CommonJS ### 📌 Merkmale von CommonJS
| Merkmal | CommonJS | | Merkmal | CommonJS |
| ------------------------- | -------------------------- | | ------------------------- | -------------------------- |
| Import-Syntax | `require()` | | Import-Syntax | `require()` |
| Export-Syntax | `module.exports = …` | | Export-Syntax | `module.exports = …` |
| Dateiendung | `.js` (keine `.mjs` nötig) | | Dateiendung | `.js` (keine `.mjs` nötig) |
| Direkt ausführbar | ✅ Ohne zusätzliche Flags | | Direkt ausführbar | ✅ Ohne zusätzliche Flags |
| `__dirname`, `__filename` | ✅ verfügbar | | `__dirname`, `__filename` | ✅ verfügbar |
| Browserkompatibilität | ❌ Nur mit Bundler möglich | | Browserkompatibilität | ❌ Nur mit Bundler möglich |
| Dynamische Importe | ✅ `require(dynamicPath)` | | Dynamische Importe | ✅ `require(dynamicPath)` |
| Tree Shaking | ❌ nicht möglich | | Tree Shaking | ❌ nicht möglich |
--- ---
### ✅ Fazit CommonJS ### ✅ Fazit CommonJS
> **CommonJS ist stabil, weit verbreitet und maximal kompatibel.** > **CommonJS ist stabil, weit verbreitet und maximal kompatibel.**
> Wenn du **einfach nur ein Node-Tool oder CLI-Skript baust** und keine besonderen Build-Prozesse oder Browser-Kompatibilität brauchst: **Nutze CommonJS.** > Wenn du **einfach nur ein Node-Tool oder CLI-Skript baust** und keine besonderen Build-Prozesse oder Browser-Kompatibilität brauchst: **Nutze CommonJS.**
Für moderne ESM-Projekte im Web oder wenn du zukunftssicher entwickeln willst, solltest du auf ESM setzen aber CJS bleibt in vielen Fällen die einfachste und robusteste Wahl. Für moderne ESM-Projekte im Web oder wenn du zukunftssicher entwickeln willst, solltest du auf ESM setzen aber CJS bleibt in vielen Fällen die einfachste und robusteste Wahl.
--- ---
## 📄 Fazit: Empfehlungen ## 📄 Fazit: Empfehlungen
- **Neue Projekte:** Nutze ESM mit `"type": "module"` - **Neue Projekte:** Nutze ESM mit `"type": "module"`
- **Bestehende Tools nutzen `require()`?** Dann CJS - **Bestehende Tools nutzen `require()`?** Dann CJS
- **Browser + Node gemeinsam nutzen?** ESM-only + klare Trennung von `shared/`, `client/`, `server/` - **Browser + Node gemeinsam nutzen?** ESM-only + klare Trennung von `shared/`, `client/`, `server/`
- **Tooling wie Vite, Nuxt, Webpack?** Immer ESM - **Tooling wie Vite, Nuxt, Webpack?** Immer ESM
--- ---
## 📁 Dateiendungen in Node.js ## 📁 Dateiendungen in Node.js
| Dateiendung | Verhalten | | Dateiendung | Verhalten |
| ----------- | ------------------- | | ----------- | ------------------- |
| `.js` | Hängt von `type` ab | | `.js` | Hängt von `type` ab |
| `.mjs` | Immer ESM | | `.mjs` | Immer ESM |
| `.cjs` | Immer CommonJS | | `.cjs` | Immer CommonJS |
--- ---
## ⚠️ Typische Fehler vermeiden ## ⚠️ Typische Fehler vermeiden
- **`SyntaxError: Cannot use import statement outside a module`** - **`SyntaxError: Cannot use import statement outside a module`**
`type` fehlt in `package.json` `type` fehlt in `package.json`
- **`Cannot find module` bei relativen Imports** - **`Cannot find module` bei relativen Imports**
`.js` fehlt am Ende beim ESM-Import `.js` fehlt am Ende beim ESM-Import
- **`__dirname` ist not defined** - **`__dirname` ist not defined**
→ Du nutzt ESM, verwende `import.meta.url` → Du nutzt ESM, verwende `import.meta.url`
--- ---
## 🚀 CLI-Build-Tipps (tsc) ## 🚀 CLI-Build-Tipps (tsc)
```bash ```bash
npx tsc # Kompiliert Projekt laut tsconfig.json npx tsc # Kompiliert Projekt laut tsconfig.json
chmod +x dist/index.js # Macht CLI-Datei ausführbar chmod +x dist/index.js # Macht CLI-Datei ausführbar
``` ```
Header für CLI-Datei: Header für CLI-Datei:
```ts ```ts
#!/usr/bin/env node #!/usr/bin/env node
``` ```
--- ---
## 📍 Weiterführende Themen ## 📍 Weiterführende Themen
- Dual-Exports für NPM (ESM + CJS gleichzeitig) - Dual-Exports für NPM (ESM + CJS gleichzeitig)
- "exports"-Feld in `package.json` - "exports"-Feld in `package.json`
- Tools wie `tsup`, `vite`, `esbuild` als Alternativen zu `tsc` - Tools wie `tsup`, `vite`, `esbuild` als Alternativen zu `tsc`
- Einstieg in CLI-Tools: `commander`, `yargs`, `chalk`, `ora` - Einstieg in CLI-Tools: `commander`, `yargs`, `chalk`, `ora`

View File

@ -1,64 +1,64 @@
# Gewindetabellen # Gewindetabellen
## 📏 **Praxis-Gewindetabelle (zöllig, G = BSPP)** ## 📏 **Praxis-Gewindetabelle (zöllig, G = BSPP)**
| Gewindebezeichnung | ⌀ Außengewinde (mm) | ⌀ Innengewinde (mm) | Typische Anwendung | | Gewindebezeichnung | ⌀ Außengewinde (mm) | ⌀ Innengewinde (mm) | Typische Anwendung |
| ------------------ | ------------------- | ------------------- | ---------------------------------- | | ------------------ | ------------------- | ------------------- | ---------------------------------- |
| **G 1/8"** | \~9,7mm | \~8,5mm | Druckluft, Manometer | | **G 1/8"** | \~9,7mm | \~8,5mm | Druckluft, Manometer |
| **G 1/4"** | \~13,2mm | \~11,5mm | Kleingeräte, Kaffeemaschinen | | **G 1/4"** | \~13,2mm | \~11,5mm | Kleingeräte, Kaffeemaschinen |
| **G 3/8"** | \~16,6mm | \~14,5mm | Geräteventile, Mini-Zulaufschlauch | | **G 3/8"** | \~16,6mm | \~14,5mm | Geräteventile, Mini-Zulaufschlauch |
| **G 1/2"** | \~20,95mm | \~18,6mm | Wasserhahn, Spülarmatur | | **G 1/2"** | \~20,95mm | \~18,6mm | Wasserhahn, Spülarmatur |
| **G 3/4"** | \~26,4mm | \~24,0mm | Waschmaschine, Gartenschlauch | | **G 3/4"** | \~26,4mm | \~24,0mm | Waschmaschine, Gartenschlauch |
| **G 1"** | \~33,25mm | \~30,3mm | Gartenwasserleitungen, Heizkreise | | **G 1"** | \~33,25mm | \~30,3mm | Gartenwasserleitungen, Heizkreise |
| **G 1 1/4"** | \~41,9mm | \~38,8mm | Hausanschluss, Regenwassernutzung | | **G 1 1/4"** | \~41,9mm | \~38,8mm | Hausanschluss, Regenwassernutzung |
--- ---
### 📌 Hinweise ### 📌 Hinweise
- Die Werte sind **gemittelte Praxiswerte**. Es gibt leichte Toleranzen je nach Hersteller. - Die Werte sind **gemittelte Praxiswerte**. Es gibt leichte Toleranzen je nach Hersteller.
- Es handelt sich um **zylindrische Whitworth-Rohrgewinde (BSPP / G)**, **nicht kegelig**. - Es handelt sich um **zylindrische Whitworth-Rohrgewinde (BSPP / G)**, **nicht kegelig**.
- Zur **Identifikation** reicht in der Regel eine Schieblehre und ein Blick in diese Tabelle. - Zur **Identifikation** reicht in der Regel eine Schieblehre und ein Blick in diese Tabelle.
- Die Angabe „Zoll“ hat **nichts** mit dem Außendurchmesser zu tun das ist reine Gewindeklassifizierung aus der Rohrnorm. - Die Angabe „Zoll“ hat **nichts** mit dem Außendurchmesser zu tun das ist reine Gewindeklassifizierung aus der Rohrnorm.
--- ---
Klar hier kommt eine **praxisorientierte Bohrtabelle für metrische ISO-Gewinde (M-Gewinde)** von **M1 bis M12**, wie sie beim Innengewindeschneiden (z.B. per Hand mit Schneideisen oder Gewindebohrer) verwendet wird. Klar hier kommt eine **praxisorientierte Bohrtabelle für metrische ISO-Gewinde (M-Gewinde)** von **M1 bis M12**, wie sie beim Innengewindeschneiden (z.B. per Hand mit Schneideisen oder Gewindebohrer) verwendet wird.
--- ---
## 📏 **Bohrtabelle für metrische ISO-Regelgewinde (M-Gewinde nach DIN 13-1)** ## 📏 **Bohrtabelle für metrische ISO-Regelgewinde (M-Gewinde nach DIN 13-1)**
| Gewinde | Steigung (mm) | Kernloch-Ø (mm) (Bohrerdurchmesser) | Hinweis | | Gewinde | Steigung (mm) | Kernloch-Ø (mm) (Bohrerdurchmesser) | Hinweis |
| ------- | ------------- | ----------------------------------- | ---------------------- | | ------- | ------------- | ----------------------------------- | ---------------------- |
| M1 | 0.25 | 0.75 | selten, Feinmechanik | | M1 | 0.25 | 0.75 | selten, Feinmechanik |
| M1.2 | 0.25 | 0.95 | z.B. Elektronik | | M1.2 | 0.25 | 0.95 | z.B. Elektronik |
| M1.6 | 0.35 | 1.25 | sehr fein | | M1.6 | 0.35 | 1.25 | sehr fein |
| M2 | 0.4 | 1.6 | Standard M2 | | M2 | 0.4 | 1.6 | Standard M2 |
| M2.5 | 0.45 | 2.05 | beliebt bei Modellbau | | M2.5 | 0.45 | 2.05 | beliebt bei Modellbau |
| M3 | 0.5 | 2.5 | sehr verbreitet | | M3 | 0.5 | 2.5 | sehr verbreitet |
| M4 | 0.7 | 3.3 | Klassiker | | M4 | 0.7 | 3.3 | Klassiker |
| M5 | 0.8 | 4.2 | oft bei Maschinen | | M5 | 0.8 | 4.2 | oft bei Maschinen |
| M6 | 1.0 | 5.0 | Standardgröße | | M6 | 1.0 | 5.0 | Standardgröße |
| M7 | 1.0 | 6.0 | eher selten | | M7 | 1.0 | 6.0 | eher selten |
| M8 | 1.25 | 6.8 | Standard M8 | | M8 | 1.25 | 6.8 | Standard M8 |
| M9 | 1.25 | 7.8 | Sondermaß | | M9 | 1.25 | 7.8 | Sondermaß |
| M10 | 1.5 | 8.5 | Maschinenbau | | M10 | 1.5 | 8.5 | Maschinenbau |
| M11 | 1.5 | 9.5 | selten | | M11 | 1.5 | 9.5 | selten |
| M12 | 1.75 | 10.2 | oft für tragende Teile | | M12 | 1.75 | 10.2 | oft für tragende Teile |
--- ---
### 📌 Hinweise Bohrtabelle ### 📌 Hinweise Bohrtabelle
- Dies sind die **Regelgewinde** bei **Feingewinden** (z.B. M10x1) brauchst du kleinere Bohrer. - Dies sind die **Regelgewinde** bei **Feingewinden** (z.B. M10x1) brauchst du kleinere Bohrer.
- Werte gelten für **100% Gewindeüberdeckung**. In der Praxis reicht oft eine leicht größere Bohrung für leichtere Schnitte (z.B. bei Alu oder weichen Werkstoffen). - Werte gelten für **100% Gewindeüberdeckung**. In der Praxis reicht oft eine leicht größere Bohrung für leichtere Schnitte (z.B. bei Alu oder weichen Werkstoffen).
- Bei harter Werkstoffwahl ggf. Spiralbohrer vorher anspitzen oder mit Zentrierbohrer vorbohren. - Bei harter Werkstoffwahl ggf. Spiralbohrer vorher anspitzen oder mit Zentrierbohrer vorbohren.
--- ---
### 🧰 Beispiel zur Borhtabelle ### 🧰 Beispiel zur Borhtabelle
Du willst ein **M6-Gewinde** schneiden? → **5,0mm Bohrer** nehmen → dann Gewindebohrer M6 einsetzen. Du willst ein **M6-Gewinde** schneiden? → **5,0mm Bohrer** nehmen → dann Gewindebohrer M6 einsetzen.
--- ---

View File

@ -1,108 +1,108 @@
# Let's Encrypt: Fehlerbehebung bei Challenge-Timeout unter Plesk # Let's Encrypt: Fehlerbehebung bei Challenge-Timeout unter Plesk
- [Let's Encrypt: Fehlerbehebung bei Challenge-Timeout unter Plesk](#lets-encrypt-fehlerbehebung-bei-challenge-timeout-unter-plesk) - [Let's Encrypt: Fehlerbehebung bei Challenge-Timeout unter Plesk](#lets-encrypt-fehlerbehebung-bei-challenge-timeout-unter-plesk)
- [🧩 Problemstellung](#-problemstellung) - [🧩 Problemstellung](#-problemstellung)
- [🧠 Ursache](#-ursache) - [🧠 Ursache](#-ursache)
- [✅ Lösung](#-lösung) - [✅ Lösung](#-lösung)
- [📍 Schritt-für-Schritt-Anleitung in Plesk:](#-schritt-für-schritt-anleitung-in-plesk) - [📍 Schritt-für-Schritt-Anleitung in Plesk:](#-schritt-für-schritt-anleitung-in-plesk)
- [🔎 Test](#-test) - [🔎 Test](#-test)
- [🔁 Danach](#-danach) - [🔁 Danach](#-danach)
- [✅ Status: **Funktioniert**](#-status-funktioniert) - [✅ Status: **Funktioniert**](#-status-funktioniert)
## 🧩 Problemstellung ## 🧩 Problemstellung
Bei der Ausstellung eines SSL/TLS-Zertifikats für `gamingblogs.de` in Plesk trat folgender Fehler auf: Bei der Ausstellung eines SSL/TLS-Zertifikats für `gamingblogs.de` in Plesk trat folgender Fehler auf:
```text ```text
Let's Encrypt-SSL/TLS-Zertifikat konnte nicht ausgestellt werden. Let's Encrypt-SSL/TLS-Zertifikat konnte nicht ausgestellt werden.
Detail: Timeout during connect (likely firewall problem) Detail: Timeout during connect (likely firewall problem)
``` ```
Trotz funktionierendem Webserver und anderen Domains auf dem gleichen Server schlug die Zertifikatsanforderung fehl. Trotz funktionierendem Webserver und anderen Domains auf dem gleichen Server schlug die Zertifikatsanforderung fehl.
--- ---
## 🧠 Ursache ## 🧠 Ursache
Let's Encrypt konnte die Validierungs-URL Let's Encrypt konnte die Validierungs-URL
```text ```text
[http://gamingblogs.de/.well-known/acme-challenge/](http://gamingblogs.de/.well-known/acme-challenge/)<token> [http://gamingblogs.de/.well-known/acme-challenge/](http://gamingblogs.de/.well-known/acme-challenge/)<token>
``` ```
nicht erfolgreich aufrufen, weil der Webserver **alle HTTP-Anfragen sofort auf HTTPS umgeleitet hat**, obwohl noch **kein gültiges Zertifikat** vorhanden war. nicht erfolgreich aufrufen, weil der Webserver **alle HTTP-Anfragen sofort auf HTTPS umgeleitet hat**, obwohl noch **kein gültiges Zertifikat** vorhanden war.
--- ---
## ✅ Lösung ## ✅ Lösung
Damit Let's Encrypt den Challenge-Pfad über HTTP erreichen kann, muss der HTTPS-Redirect **ausgenommen werden**. Damit Let's Encrypt den Challenge-Pfad über HTTP erreichen kann, muss der HTTPS-Redirect **ausgenommen werden**.
### 📍 Schritt-für-Schritt-Anleitung in Plesk: ### 📍 Schritt-für-Schritt-Anleitung in Plesk:
1. Öffne **Plesk** 1. Öffne **Plesk**
2. Navigiere zu 2. Navigiere zu
`Websites & Domains → gamingblogs.de → Apache & nginx-Einstellungen` `Websites & Domains → gamingblogs.de → Apache & nginx-Einstellungen`
3. Scrolle zu **"Zusätzliche Apache-Anweisungen"** 3. Scrolle zu **"Zusätzliche Apache-Anweisungen"**
4. Trage Folgendes in **beide Felder (HTTP und HTTPS)** ein: 4. Trage Folgendes in **beide Felder (HTTP und HTTPS)** ein:
```apache ```apache
<IfModule mod_rewrite.c> <IfModule mod_rewrite.c>
RewriteEngine On RewriteEngine On
RewriteCond %{REQUEST_URI} ^/\.well-known/acme-challenge/ [NC] RewriteCond %{REQUEST_URI} ^/\.well-known/acme-challenge/ [NC]
RewriteRule ^ - [L] RewriteRule ^ - [L]
</IfModule> </IfModule>
``` ```
5. Falls ein HTTP-zu-HTTPS-Redirect aktiv ist, ergänze **nur im HTTP-Feld**: 5. Falls ein HTTP-zu-HTTPS-Redirect aktiv ist, ergänze **nur im HTTP-Feld**:
```apache ```apache
<IfModule mod_rewrite.c> <IfModule mod_rewrite.c>
RewriteEngine On RewriteEngine On
RewriteCond %{REQUEST_URI} ^/\.well-known/acme-challenge/ [NC] RewriteCond %{REQUEST_URI} ^/\.well-known/acme-challenge/ [NC]
RewriteRule ^ - [L] RewriteRule ^ - [L]
RewriteCond %{HTTPS} off RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule> </IfModule>
``` ```
6. Speichern und warten, bis Plesk die Konfiguration neu lädt 6. Speichern und warten, bis Plesk die Konfiguration neu lädt
--- ---
## 🔎 Test ## 🔎 Test
Vom externen System: Vom externen System:
```bash ```bash
curl -I http://gamingblogs.de/.well-known/acme-challenge/test curl -I http://gamingblogs.de/.well-known/acme-challenge/test
``` ```
**Erwartetes Ergebnis:** **Erwartetes Ergebnis:**
```http ```http
HTTP/1.1 404 Not Found HTTP/1.1 404 Not Found
``` ```
⚠️ Kein Redirect auf HTTPS, kein Timeout → Let's Encrypt kann jetzt validieren. ⚠️ Kein Redirect auf HTTPS, kein Timeout → Let's Encrypt kann jetzt validieren.
--- ---
## 🔁 Danach ## 🔁 Danach
In Plesk: In Plesk:
1. Zurück zu `Websites & Domains → gamingblogs.de` 1. Zurück zu `Websites & Domains → gamingblogs.de`
2. Auf **"SSL/TLS-Zertifikat" (Let's Encrypt)** klicken 2. Auf **"SSL/TLS-Zertifikat" (Let's Encrypt)** klicken
3. Zertifikat neu **beantragen** 3. Zertifikat neu **beantragen**
4. Erfolgreiche Ausstellung wird bestätigt 4. Erfolgreiche Ausstellung wird bestätigt
--- ---
## ✅ Status: **Funktioniert** ## ✅ Status: **Funktioniert**
Datum der Umsetzung: 2025-05-22 Datum der Umsetzung: 2025-05-22

View File

@ -1,52 +1,52 @@
# Plesk ausgesperrt bei Rechnerwechsel # Plesk ausgesperrt bei Rechnerwechsel
## Inhalt ## Inhalt
- [Plesk ausgesperrt bei Rechnerwechsel](#plesk-ausgesperrt-bei-rechnerwechsel) - [Plesk ausgesperrt bei Rechnerwechsel](#plesk-ausgesperrt-bei-rechnerwechsel)
- [Inhalt](#inhalt) - [Inhalt](#inhalt)
- [Problembeschreibung](#problembeschreibung) - [Problembeschreibung](#problembeschreibung)
- [Workarround](#workarround) - [Workarround](#workarround)
- [Nachhaltige Lösung des Problems](#nachhaltige-lösung-des-problems) - [Nachhaltige Lösung des Problems](#nachhaltige-lösung-des-problems)
## Problembeschreibung ## Problembeschreibung
Es kommt öfter vor, das ich aus der Plesk Weboberfläche automatisch ausgeloggt werde und ein erneuter Login anschliessend nicht mehr möglich ist. Es kommt öfter vor, das ich aus der Plesk Weboberfläche automatisch ausgeloggt werde und ein erneuter Login anschliessend nicht mehr möglich ist.
Die genaue Ursache ist mir nicht eindeutig bekannt aber ich vermute das im Browser irgendwelche Sessions gelöscht werden. Die genaue Ursache ist mir nicht eindeutig bekannt aber ich vermute das im Browser irgendwelche Sessions gelöscht werden.
Als erstes habe ich in meinem Brave-Browser den Schutz für explizit diese Seite deaktiviert. Als erstes habe ich in meinem Brave-Browser den Schutz für explizit diese Seite deaktiviert.
Um mich wieder einloggen zu können, muss ich die Session auf dem Server von hand aus der Datenbank löschen. Um mich wieder einloggen zu können, muss ich die Session auf dem Server von hand aus der Datenbank löschen.
### Workarround ### Workarround
**Plesk Version:** Plesk Obsidian Web Admin Edition 18.0.70 **Plesk Version:** Plesk Obsidian Web Admin Edition 18.0.70
Bei Plesk gibt es manchmal die gloreiche Meldung: Bei Plesk gibt es manchmal die gloreiche Meldung:
> Sie konnten nicht angemeldet werden. > Sie konnten nicht angemeldet werden.
> **Ein anderer Benutzer mit demselben Benutzernamen (benutzername) ist bereits bei Plesk angemeldet.** > **Ein anderer Benutzer mit demselben Benutzernamen (benutzername) ist bereits bei Plesk angemeldet.**
Ärgerlich wenn das gerade der Adminzugang ist. Ärgerlich wenn das gerade der Adminzugang ist.
Falls Du gerade noch SSH Zugang hast dann: Falls Du gerade noch SSH Zugang hast dann:
login und wechsel zum root, anschliessend: login und wechsel zum root, anschliessend:
```bash ```bash
plesk db "DELETE FROM sessions WHERE login = 'admin';" plesk db "DELETE FROM sessions WHERE login = 'admin';"
``` ```
**oder** **oder**
```bash ```bash
mysql -uadmin -p$(cat /etc/psa/.psa.shadow) psa -e "DELETE FROM sessions WHERE login = 'admin';" mysql -uadmin -p$(cat /etc/psa/.psa.shadow) psa -e "DELETE FROM sessions WHERE login = 'admin';"
``` ```
anschliessend: anschliessend:
```bash ```bash
systemctl restart psa systemctl restart psa
``` ```
und dann ganz normal Login wie gewohnt. und dann ganz normal Login wie gewohnt.
### Nachhaltige Lösung des Problems ### Nachhaltige Lösung des Problems
aktuell nicht bekannt! aktuell nicht bekannt!

View File

@ -1,152 +1,152 @@
# Erstellung eines Installationsmediums für Rust + MSVC (Offline) # Erstellung eines Installationsmediums für Rust + MSVC (Offline)
Dieser Artikel beschreibt, wie du ein **vollständiges Installationsmedium** für die **Rust-Toolchain mit MSVC** unter Windows vorbereitest, damit du Rust auf anderen Rechnern **ohne Internetzugang** einrichten kannst. Dieser Artikel beschreibt, wie du ein **vollständiges Installationsmedium** für die **Rust-Toolchain mit MSVC** unter Windows vorbereitest, damit du Rust auf anderen Rechnern **ohne Internetzugang** einrichten kannst.
--- ---
## Ziel ## Ziel
Ein USB-Stick oder Offline-Verzeichnis mit: Ein USB-Stick oder Offline-Verzeichnis mit:
- Rust-Installer (offlinefähig) - Rust-Installer (offlinefähig)
- Visual Studio Build Tools (komplett inkl. MSVC) - Visual Studio Build Tools (komplett inkl. MSVC)
- Optional: vorkompilierte Ziel-Toolchains - Optional: vorkompilierte Ziel-Toolchains
--- ---
## 1. Rust Offline-Installer vorbereiten ## 1. Rust Offline-Installer vorbereiten
### 1.1 Rustup Offline-Installer besorgen ### 1.1 Rustup Offline-Installer besorgen
Gehe auf: Gehe auf:
https://forge.rust-lang.org/infra/release-archives.html https://forge.rust-lang.org/infra/release-archives.html
Lade von dort: Lade von dort:
- `rust-<version>-x86_64-pc-windows-msvc.msi` - `rust-<version>-x86_64-pc-windows-msvc.msi`
- `cargo-<version>-x86_64-pc-windows-msvc.msi` (optional) - `cargo-<version>-x86_64-pc-windows-msvc.msi` (optional)
Oder direkt über: Oder direkt über:
https://static.rust-lang.org/dist/ https://static.rust-lang.org/dist/
### 1.2 Installation ohne Internet ### 1.2 Installation ohne Internet
Auf dem Zielrechner: Auf dem Zielrechner:
- Führe `.msi`-Datei lokal aus - Führe `.msi`-Datei lokal aus
- Setze den `Path` manuell oder automatisch via Skript - Setze den `Path` manuell oder automatisch via Skript
--- ---
## 2. Visual Studio Build Tools offline installieren ## 2. Visual Studio Build Tools offline installieren
### 2.1 Installer herunterladen ### 2.1 Installer herunterladen
Lade den **Visual Studio Installer** von: Lade den **Visual Studio Installer** von:
https://visualstudio.microsoft.com/de/visual-cpp-build-tools/ https://visualstudio.microsoft.com/de/visual-cpp-build-tools/
Starte dann: Starte dann:
```cmd ```cmd
vs_BuildTools.exe --layout C:\VSOffline --lang de-DE vs_BuildTools.exe --layout C:\VSOffline --lang de-DE
``` ```
Dieser Befehl erstellt einen vollständigen Offline-Installer im Verzeichnis `C:\VSOffline`. Dieser Befehl erstellt einen vollständigen Offline-Installer im Verzeichnis `C:\VSOffline`.
### 2.2 Auswahl der Workloads ### 2.2 Auswahl der Workloads
Wähle beim interaktiven Download (GUI oder CLI): Wähle beim interaktiven Download (GUI oder CLI):
- **C++ Build Tools** - **C++ Build Tools**
- Workload-Komponenten: - Workload-Komponenten:
- MSVC v14.x (x64/x86) - MSVC v14.x (x64/x86)
- Windows 10/11 SDK - Windows 10/11 SDK
- CMake-Tools (optional) - CMake-Tools (optional)
> 💡 Achtung: Download-Größe ca. 46GB! > 💡 Achtung: Download-Größe ca. 46GB!
### 2.3 Installation auf Zielsystem (Offline) ### 2.3 Installation auf Zielsystem (Offline)
Auf dem Zielrechner: Auf dem Zielrechner:
```cmd ```cmd
C:\VSOffline\vs_BuildTools.exe --noweb --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --quiet --wait C:\VSOffline\vs_BuildTools.exe --noweb --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --quiet --wait
``` ```
Alternativ über `vs_setup.exe`, je nach Version. Alternativ über `vs_setup.exe`, je nach Version.
--- ---
## 3. Optional: Toolchains, Crates & Targets vorbereiten ## 3. Optional: Toolchains, Crates & Targets vorbereiten
Falls du zusätzliche Targets (z.B. Linux oder ARM) brauchst: Falls du zusätzliche Targets (z.B. Linux oder ARM) brauchst:
### 3.1 Ziel-Toolchain lokal laden ### 3.1 Ziel-Toolchain lokal laden
```cmd ```cmd
rustup target add x86_64-unknown-linux-gnu --print rustup target add x86_64-unknown-linux-gnu --print
``` ```
Lade die `.tar.gz` von: Lade die `.tar.gz` von:
https://static.rust-lang.org/dist/ https://static.rust-lang.org/dist/
Speichere diese im `dist/`-Ordner und installiere offline via: Speichere diese im `dist/`-Ordner und installiere offline via:
```cmd ```cmd
rustup toolchain link <name> <pfad_zur_toolchain> rustup toolchain link <name> <pfad_zur_toolchain>
``` ```
--- ---
## 4. Automatisierung via USB-Stick ## 4. Automatisierung via USB-Stick
### Dateistruktur auf Stick ### Dateistruktur auf Stick
```text ```text
USB-STICK/ USB-STICK/
├── rust/ ├── rust/
│ └── rust-1.xx.x-x86_64-pc-windows-msvc.msi │ └── rust-1.xx.x-x86_64-pc-windows-msvc.msi
├── vsbuildtools/ ├── vsbuildtools/
│ └── setup + Offline-Daten │ └── setup + Offline-Daten
├── install.cmd ├── install.cmd
``` ```
### Beispiel `install.cmd` ### Beispiel `install.cmd`
```cmd ```cmd
@echo off @echo off
echo [1/2] Installiere Rust... echo [1/2] Installiere Rust...
start /wait rust\rust-*.msi start /wait rust\rust-*.msi
echo [2/2] Installiere Visual Studio Build Tools... echo [2/2] Installiere Visual Studio Build Tools...
start /wait vsbuildtools\vs_BuildTools.exe --noweb --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --quiet --wait start /wait vsbuildtools\vs_BuildTools.exe --noweb --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --quiet --wait
echo Fertig. Bitte PC neu starten! echo Fertig. Bitte PC neu starten!
pause pause
``` ```
--- ---
## 5. Validierung ## 5. Validierung
Nach der Offline-Installation auf Zielsystem: Nach der Offline-Installation auf Zielsystem:
```cmd ```cmd
cargo new testprojekt cargo new testprojekt
cd testprojekt cd testprojekt
cargo build --release cargo build --release
``` ```
Ergebnis: Ergebnis:
target\release\testprojekt.exe target\release\testprojekt.exe
--- ---
## Fazit ## Fazit
Mit dieser Methode kannst du eine vollständige Rust- und MSVC-Umgebung offline auf jedem Windows-System aufsetzen ideal für abgeschottete Systeme ohne Internetverbindung. Mit dieser Methode kannst du eine vollständige Rust- und MSVC-Umgebung offline auf jedem Windows-System aufsetzen ideal für abgeschottete Systeme ohne Internetverbindung.

View File

@ -1,152 +1,152 @@
# Rust-Toolchain mit MSVC unter Windows einrichten # Rust-Toolchain mit MSVC unter Windows einrichten
Dieser Artikel beschreibt die vollständige Einrichtung einer produktionsfähigen Rust-Toolchain mit **MSVC (Microsoft Visual C++)** unter **Windows**, einschließlich Erstellung einer `.exe`-Datei aus einem Beispielprogramm. Dieser Artikel beschreibt die vollständige Einrichtung einer produktionsfähigen Rust-Toolchain mit **MSVC (Microsoft Visual C++)** unter **Windows**, einschließlich Erstellung einer `.exe`-Datei aus einem Beispielprogramm.
## Inhalt ## Inhalt
- [Rust-Toolchain mit MSVC unter Windows einrichten](#rust-toolchain-mit-msvc-unter-windows-einrichten) - [Rust-Toolchain mit MSVC unter Windows einrichten](#rust-toolchain-mit-msvc-unter-windows-einrichten)
- [Inhalt](#inhalt) - [Inhalt](#inhalt)
- [Voraussetzungen](#voraussetzungen) - [Voraussetzungen](#voraussetzungen)
- [1. Rust installieren](#1-rust-installieren) - [1. Rust installieren](#1-rust-installieren)
- [2. Visual Studio Build Tools installieren](#2-visual-studio-build-tools-installieren) - [2. Visual Studio Build Tools installieren](#2-visual-studio-build-tools-installieren)
- [Schritt-für-Schritt](#schritt-für-schritt) - [Schritt-für-Schritt](#schritt-für-schritt)
- [3. Umgebungsvariablen setzen (optional)](#3-umgebungsvariablen-setzen-optional) - [3. Umgebungsvariablen setzen (optional)](#3-umgebungsvariablen-setzen-optional)
- [4. Beispielprojekt erstellen](#4-beispielprojekt-erstellen) - [4. Beispielprojekt erstellen](#4-beispielprojekt-erstellen)
- [5. Projekt kompilieren](#5-projekt-kompilieren) - [5. Projekt kompilieren](#5-projekt-kompilieren)
- [Debug-Build (schnell, nicht optimiert)](#debug-build-schnell-nicht-optimiert) - [Debug-Build (schnell, nicht optimiert)](#debug-build-schnell-nicht-optimiert)
- [Release-Build (optimiert, kleine `.exe`)](#release-build-optimiert-kleine-exe) - [Release-Build (optimiert, kleine `.exe`)](#release-build-optimiert-kleine-exe)
- [6. Optional: `.exe` testen](#6-optional-exe-testen) - [6. Optional: `.exe` testen](#6-optional-exe-testen)
- [7. Troubleshooting](#7-troubleshooting) - [7. Troubleshooting](#7-troubleshooting)
- [8. Alternative: Toolchain in einem Offline-Installer vorbereiten](#8-alternative-toolchain-in-einem-offline-installer-vorbereiten) - [8. Alternative: Toolchain in einem Offline-Installer vorbereiten](#8-alternative-toolchain-in-einem-offline-installer-vorbereiten)
- [Zusammenfassung](#zusammenfassung) - [Zusammenfassung](#zusammenfassung)
- [Weiterführende Themen](#weiterführende-themen) - [Weiterführende Themen](#weiterführende-themen)
--- ---
## Voraussetzungen ## Voraussetzungen
- Windows 10 oder 11 (64 Bit) - Windows 10 oder 11 (64 Bit)
- Administratorrechte - Administratorrechte
- Mindestens 2GB freier Speicherplatz - Mindestens 2GB freier Speicherplatz
## 1. Rust installieren ## 1. Rust installieren
Lade das offizielle Rust-Installationsprogramm herunter und führe es aus: Lade das offizielle Rust-Installationsprogramm herunter und führe es aus:
<https://rustup.rs> <https://rustup.rs>
Beim Setup: Beim Setup:
- **Toolchain wählen**: `default host triple: x86_64-pc-windows-msvc` - **Toolchain wählen**: `default host triple: x86_64-pc-windows-msvc`
- Folge dem Assistenten, um `rustc`, `cargo` und `rustup` zu installieren. - Folge dem Assistenten, um `rustc`, `cargo` und `rustup` zu installieren.
Verifiziere die Installation: Verifiziere die Installation:
```shell ```shell
rustc --version rustc --version
cargo --version cargo --version
``` ```
## 2. Visual Studio Build Tools installieren ## 2. Visual Studio Build Tools installieren
Die Rust-Toolchain mit MSVC benötigt den **"C++ Build Tools"**-Teil von Visual Studio. Die Rust-Toolchain mit MSVC benötigt den **"C++ Build Tools"**-Teil von Visual Studio.
### Schritt-für-Schritt ### Schritt-für-Schritt
1. Lade den **Visual Studio Installer**: 1. Lade den **Visual Studio Installer**:
- <https://visualstudio.microsoft.com/de/visual-cpp-build-tools/> - <https://visualstudio.microsoft.com/de/visual-cpp-build-tools/>
2. Wähle bei der Installation: 2. Wähle bei der Installation:
- ✅ **C++ Build Tools** - ✅ **C++ Build Tools**
- Und in der rechten Spalte: - Und in der rechten Spalte:
- ✅ "MSVC v14.x - VS 2022 C++ x64/x86-Buildtools" - ✅ "MSVC v14.x - VS 2022 C++ x64/x86-Buildtools"
- ✅ "Windows 10 SDK" oder "Windows 11 SDK" (je nach Zielsystem) - ✅ "Windows 10 SDK" oder "Windows 11 SDK" (je nach Zielsystem)
- ✅ "C++ CMake-Tools für Windows" (optional für CMake-Projekte) - ✅ "C++ CMake-Tools für Windows" (optional für CMake-Projekte)
3. Installiere alles und starte das System neu, falls verlangt. 3. Installiere alles und starte das System neu, falls verlangt.
## 3. Umgebungsvariablen setzen (optional) ## 3. Umgebungsvariablen setzen (optional)
Falls du die Buildtools über Kommandozeile verwenden willst, öffne: Falls du die Buildtools über Kommandozeile verwenden willst, öffne:
```cmd ```cmd
"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat" "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"
``` ```
Das setzt temporär alle notwendigen Umgebungsvariablen für den Build-Prozess. Das setzt temporär alle notwendigen Umgebungsvariablen für den Build-Prozess.
## 4. Beispielprojekt erstellen ## 4. Beispielprojekt erstellen
```cmd ```cmd
cargo new hello_world cargo new hello_world
cd hello_world cd hello_world
``` ```
Beispielcode in `src/main.rs`: Beispielcode in `src/main.rs`:
```rust ```rust
fn main() { fn main() {
println!("Hallo Welt kompiliert mit MSVC!"); println!("Hallo Welt kompiliert mit MSVC!");
} }
``` ```
## 5. Projekt kompilieren ## 5. Projekt kompilieren
### Debug-Build (schnell, nicht optimiert) ### Debug-Build (schnell, nicht optimiert)
```cmd ```cmd
cargo build cargo build
``` ```
### Release-Build (optimiert, kleine `.exe`) ### Release-Build (optimiert, kleine `.exe`)
```cmd ```cmd
cargo build --release cargo build --release
``` ```
Die fertige `.exe` liegt unter: Die fertige `.exe` liegt unter:
.\target\release\hello_world.exe .\target\release\hello_world.exe
## 6. Optional: `.exe` testen ## 6. Optional: `.exe` testen
```cmd ```cmd
.\target\release\hello_world.exe .\target\release\hello_world.exe
``` ```
## 7. Troubleshooting ## 7. Troubleshooting
- **Fehlermeldung `link.exe not found`?** - **Fehlermeldung `link.exe not found`?**
→ Build-Tools sind nicht korrekt installiert (siehe Schritt 2) → Build-Tools sind nicht korrekt installiert (siehe Schritt 2)
- **Fehlermeldung zu fehlendem SDK?** - **Fehlermeldung zu fehlendem SDK?**
→ Stelle sicher, dass du das passende Windows SDK mit installiert hast → Stelle sicher, dass du das passende Windows SDK mit installiert hast
- **MSVC und GNU Toolchain gleichzeitig installiert?** - **MSVC und GNU Toolchain gleichzeitig installiert?**
→ Du kannst über `rustup` zwischen beiden wechseln: → Du kannst über `rustup` zwischen beiden wechseln:
```cmd ```cmd
rustup show rustup show
rustup default stable-x86_64-pc-windows-msvc rustup default stable-x86_64-pc-windows-msvc
``` ```
## 8. Alternative: Toolchain in einem Offline-Installer vorbereiten ## 8. Alternative: Toolchain in einem Offline-Installer vorbereiten
Wenn du das Setup auf mehreren Rechnern ohne Internetzugang durchführen möchtest, siehe [separater Artikel zur Erstellung eines Installationsmediums](./rust-offline-installation.md). Wenn du das Setup auf mehreren Rechnern ohne Internetzugang durchführen möchtest, siehe [separater Artikel zur Erstellung eines Installationsmediums](./rust-offline-installation.md).
## Zusammenfassung ## Zusammenfassung
| Komponente | Aufgabe | | Komponente | Aufgabe |
|------------------|----------------------------------| |------------------|----------------------------------|
| Rustup | Verwaltung von Toolchains | | Rustup | Verwaltung von Toolchains |
| Cargo | Buildsystem und Paketmanager | | Cargo | Buildsystem und Paketmanager |
| MSVC Build Tools | C++-Compiler/Linker für Windows | | MSVC Build Tools | C++-Compiler/Linker für Windows |
| `vcvars64.bat` | Aktiviert Build-Umgebung | | `vcvars64.bat` | Aktiviert Build-Umgebung |
| `cargo build` | Erstellt `.exe` mit Rust und MSVC | | `cargo build` | Erstellt `.exe` mit Rust und MSVC |
## Weiterführende Themen ## Weiterführende Themen
- Einbindung von Ressourcen und Icons in die `.exe` - Einbindung von Ressourcen und Icons in die `.exe`
- Verwendung von `cc`/`bindgen` für C-Bindings - Verwendung von `cc`/`bindgen` für C-Bindings
- Cross-Kompilierung mit `x86_64-pc-windows-gnu` oder Linux-Zielsystemen - Cross-Kompilierung mit `x86_64-pc-windows-gnu` oder Linux-Zielsystemen
- Automatisierter Build via Makefile oder PowerShell - Automatisierter Build via Makefile oder PowerShell

View File

@ -0,0 +1,158 @@
# NGINX Proxy Manager als Reverse Proxy für Node.js-Apps
>**Letzte Änderung:** 27.06.2025
---
- [NGINX Proxy Manager als Reverse Proxy für Node.js-Apps](#nginx-proxy-manager-als-reverse-proxy-für-nodejs-apps)
- [Ziel](#ziel)
- [Voraussetzungen](#voraussetzungen)
- [Verzeichnisstruktur](#verzeichnisstruktur)
- [docker-compose.yml](#docker-composeyml)
- [Starten](#starten)
- [Zugriff auf Web-GUI](#zugriff-auf-web-gui)
- [Proxy-Host anlegen](#proxy-host-anlegen)
- [Ergebnis](#ergebnis)
- [Hinweise](#hinweise)
- [Optional: Node.js-Apps als systemd-Service verwalten](#optional-nodejs-apps-als-systemd-service-verwalten)
- [Fertig](#fertig)
---
## Ziel
- Node.js-Apps im LAN per HTTPS erreichbar machen
- Let's Encrypt Zertifikate automatisch verwalten
- Einfaches Management über Web-GUI
- Kein manuelles Bearbeiten von NGINX-Konfigurationen
---
## Voraussetzungen
- Server mit Debian 12 oder kompatibel
- Docker und Docker Compose installiert
- Ports 80/443 sind frei
- Fritzbox leitet Ports 80/443 auf den Server weiter
- Domain zeigt per A-Record auf die öffentliche IP
---
## Verzeichnisstruktur
Empfohlenes Setup unter `/opt/nginx-proxy-manager/`:
```plaintext
/opt/nginx-proxy-manager/
├── docker-compose.yml
├── data/ # Konfigurationsdaten von NGINX Proxy Manager
└── letsencrypt/ # SSL-Zertifikate
```
---
## docker-compose.yml
```yaml
version: '3'
services:
nginx-proxy-manager:
image: 'jc21/nginx-proxy-manager:latest'
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- '80:80' # HTTP
- '443:443' # HTTPS
- '81:81' # Admin UI
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
environment:
- TZ=Europe/Berlin
```
---
## Starten
```bash
cd /opt/nginx-proxy-manager
docker compose up -d
```
---
## Zugriff auf Web-GUI
- URL: `http://<SERVER-IP>:81`
- Standard-Zugang:
- Benutzer: `admin@example.com`
- Passwort: `changeme`
- Zugangsdaten nach erstem Login ändern.
---
## Proxy-Host anlegen
1. „Proxy Hosts“ → „Add Proxy Host“
2. Domain Name: `app1.domain.de`
3. Scheme: `http`
4. Forward Hostname/IP: `192.168.178.11`
5. Forward Port: `3000`
6. SSL aktivieren → „Request a new SSL Certificate“ → Let's Encrypt
---
## Ergebnis
- Externe Anfragen an `app1.domain.de` werden via HTTPS von NGINX Proxy Manager entgegengenommen.
- Intern wird die Anfrage an `192.168.178.11:3000` (Node.js-App) weitergeleitet.
- Zertifikate werden automatisch verwaltet.
---
## Hinweise
✅ Kein systemweiter NGINX mehr erforderlich.
✅ Ports 80/443 werden vollständig vom Container belegt.
✅ Einfach skalierbar für mehrere Domains und Apps.
✅ Wartbar über die Weboberfläche, keine manuelle Konfigurationsarbeit.
---
## Optional: Node.js-Apps als systemd-Service verwalten
Beispiel für eine Datei `/etc/systemd/system/myapp.service`:
```ini
[Unit]
Description=Meine Node.js App
After=network.target
[Service]
ExecStart=/usr/bin/node /opt/myapp/index.js
Restart=on-failure
User=www-data
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
```
Aktivieren und starten:
```bash
systemctl enable myapp
systemctl start myapp
```
---
## Fertig
Dein Setup ist jetzt produktionsbereit.

View File

@ -1,177 +1,177 @@
# Einführung in die `desktop.ini`-Datei: Verwendung und Anpassung von Ordnern in Windows # Einführung in die `desktop.ini`-Datei: Verwendung und Anpassung von Ordnern in Windows
*2025 - Adam Skotarczak* *2025 - Adam Skotarczak*
Die `desktop.ini`-Datei ist eine wichtige, jedoch wenig bekannte Datei in Windows, die zur Konfiguration und Anpassung von Ordnern verwendet wird. Sie ermöglicht es Benutzern, das Erscheinungsbild und Verhalten von Ordnern anzupassen, indem sie Einstellungen wie Symbole, Tooltips und Ordnerspezifikationen definiert. In diesem Artikel werden wir die Funktionsweise der `desktop.ini`-Datei ausführlich erklären und alle Optionen und Attribute vorstellen, die in dieser Datei verwendet werden können. Die `desktop.ini`-Datei ist eine wichtige, jedoch wenig bekannte Datei in Windows, die zur Konfiguration und Anpassung von Ordnern verwendet wird. Sie ermöglicht es Benutzern, das Erscheinungsbild und Verhalten von Ordnern anzupassen, indem sie Einstellungen wie Symbole, Tooltips und Ordnerspezifikationen definiert. In diesem Artikel werden wir die Funktionsweise der `desktop.ini`-Datei ausführlich erklären und alle Optionen und Attribute vorstellen, die in dieser Datei verwendet werden können.
## Inhaltsverzeichnis ## Inhaltsverzeichnis
- [Einführung in die `desktop.ini`-Datei: Verwendung und Anpassung von Ordnern in Windows](#einführung-in-die-desktopini-datei-verwendung-und-anpassung-von-ordnern-in-windows) - [Einführung in die `desktop.ini`-Datei: Verwendung und Anpassung von Ordnern in Windows](#einführung-in-die-desktopini-datei-verwendung-und-anpassung-von-ordnern-in-windows)
- [Inhaltsverzeichnis](#inhaltsverzeichnis) - [Inhaltsverzeichnis](#inhaltsverzeichnis)
- [Was ist die `desktop.ini`-Datei?](#was-ist-die-desktopini-datei) - [Was ist die `desktop.ini`-Datei?](#was-ist-die-desktopini-datei)
- [Grundlegende Struktur der `desktop.ini`](#grundlegende-struktur-der-desktopini) - [Grundlegende Struktur der `desktop.ini`](#grundlegende-struktur-der-desktopini)
- [Wichtige Optionen und Attribute](#wichtige-optionen-und-attribute) - [Wichtige Optionen und Attribute](#wichtige-optionen-und-attribute)
- [Optionen in der `[General]`-Sektion](#optionen-in-der-general-sektion) - [Optionen in der `[General]`-Sektion](#optionen-in-der-general-sektion)
- [Optionen in der `[View]`-Sektion](#optionen-in-der-view-sektion) - [Optionen in der `[View]`-Sektion](#optionen-in-der-view-sektion)
- [Optionen in der `[Icon]`-Sektion](#optionen-in-der-icon-sektion) - [Optionen in der `[Icon]`-Sektion](#optionen-in-der-icon-sektion)
- [Optionen in der `[LocalizedFileNames]`-Sektion](#optionen-in-der-localizedfilenames-sektion) - [Optionen in der `[LocalizedFileNames]`-Sektion](#optionen-in-der-localizedfilenames-sektion)
- [Optionen in der `[ShellClassInfo]`-Sektion](#optionen-in-der-shellclassinfo-sektion) - [Optionen in der `[ShellClassInfo]`-Sektion](#optionen-in-der-shellclassinfo-sektion)
- [Kommentare in der `desktop.ini`](#kommentare-in-der-desktopini) - [Kommentare in der `desktop.ini`](#kommentare-in-der-desktopini)
- [Die Bedeutung von Attributen und Rechten der `desktop.ini`](#die-bedeutung-von-attributen-und-rechten-der-desktopini) - [Die Bedeutung von Attributen und Rechten der `desktop.ini`](#die-bedeutung-von-attributen-und-rechten-der-desktopini)
- [Rechte für die `desktop.ini` unter Windows setzen](#rechte-für-die-desktopini-unter-windows-setzen) - [Rechte für die `desktop.ini` unter Windows setzen](#rechte-für-die-desktopini-unter-windows-setzen)
- [Verwendung der `desktop.ini` auf NAS-Laufwerken](#verwendung-der-desktopini-auf-nas-laufwerken) - [Verwendung der `desktop.ini` auf NAS-Laufwerken](#verwendung-der-desktopini-auf-nas-laufwerken)
- [Fazit](#fazit) - [Fazit](#fazit)
## Was ist die `desktop.ini`-Datei? ## Was ist die `desktop.ini`-Datei?
Die `desktop.ini`-Datei ist eine Systemdatei in Microsoft Windows, die zur Anpassung von Ordnersymbolen, Tooltips und anderen Ordnerattributen verwendet wird. Diese Datei ermöglicht es, das Aussehen und Verhalten eines Ordners zu verändern, ohne dass zusätzliche Software erforderlich ist. Sie befindet sich normalerweise im Ordner, für den sie Einstellungen vornimmt, und beeinflusst nur diesen Ordner. Die `desktop.ini`-Datei ist eine Systemdatei in Microsoft Windows, die zur Anpassung von Ordnersymbolen, Tooltips und anderen Ordnerattributen verwendet wird. Diese Datei ermöglicht es, das Aussehen und Verhalten eines Ordners zu verändern, ohne dass zusätzliche Software erforderlich ist. Sie befindet sich normalerweise im Ordner, für den sie Einstellungen vornimmt, und beeinflusst nur diesen Ordner.
## Grundlegende Struktur der `desktop.ini` ## Grundlegende Struktur der `desktop.ini`
Die `desktop.ini`-Datei ist eine INI-Datei, die aus verschiedenen Sektionen und Key-Value-Paaren besteht. Sie enthält spezifische Anweisungen für den Ordner, in dem sie sich befindet. Die wichtigsten Sektionen sind: Die `desktop.ini`-Datei ist eine INI-Datei, die aus verschiedenen Sektionen und Key-Value-Paaren besteht. Sie enthält spezifische Anweisungen für den Ordner, in dem sie sich befindet. Die wichtigsten Sektionen sind:
- `[General]`: Enthält grundlegende Informationen zum Ordner, wie den Namen und den Tooltip. - `[General]`: Enthält grundlegende Informationen zum Ordner, wie den Namen und den Tooltip.
- `[View]`: Steuert die Anzeigeeinstellungen des Ordners. - `[View]`: Steuert die Anzeigeeinstellungen des Ordners.
- `[Icon]`: Definiert das Symbol des Ordners. - `[Icon]`: Definiert das Symbol des Ordners.
- `[LocalizedFileNames]`: Bietet die Möglichkeit, Ordnernamen in verschiedenen Sprachen anzuzeigen. - `[LocalizedFileNames]`: Bietet die Möglichkeit, Ordnernamen in verschiedenen Sprachen anzuzeigen.
- `[ShellClassInfo]`: Beinhaltet erweiterte Einstellungen für den Ordner, wie das Symbol und zusätzliche Eigenschaften. - `[ShellClassInfo]`: Beinhaltet erweiterte Einstellungen für den Ordner, wie das Symbol und zusätzliche Eigenschaften.
## Wichtige Optionen und Attribute ## Wichtige Optionen und Attribute
### Optionen in der `[General]`-Sektion ### Optionen in der `[General]`-Sektion
- **`Name`**: Der Name des Ordners, der im Windows Explorer angezeigt wird. - **`Name`**: Der Name des Ordners, der im Windows Explorer angezeigt wird.
```ini ```ini
Name=Mein Ordner Name=Mein Ordner
``` ```
- **`InfoTip`**: Ein Tooltip, der angezeigt wird, wenn der Benutzer mit der Maus über den Ordner fährt. - **`InfoTip`**: Ein Tooltip, der angezeigt wird, wenn der Benutzer mit der Maus über den Ordner fährt.
```ini ```ini
InfoTip=Dies ist ein wichtiger Ordner. InfoTip=Dies ist ein wichtiger Ordner.
``` ```
### Optionen in der `[View]`-Sektion ### Optionen in der `[View]`-Sektion
- **`Mode`**: Bestimmt die Ansicht des Ordners. Mögliche Werte: - **`Mode`**: Bestimmt die Ansicht des Ordners. Mögliche Werte:
- `0`: Liste - `0`: Liste
- `1`: Details - `1`: Details
- `2`: Große Symbole - `2`: Große Symbole
- `3`: Kleine Symbole - `3`: Kleine Symbole
```ini ```ini
Mode=2 ; Setze den Ordner auf "Große Symbole" Mode=2 ; Setze den Ordner auf "Große Symbole"
``` ```
- **`FolderType`**: Bestimmt den Typ des Ordners, z. B. `Documents`, `Music`, `Pictures`. - **`FolderType`**: Bestimmt den Typ des Ordners, z. B. `Documents`, `Music`, `Pictures`.
```ini ```ini
FolderType=Documents ; Ordnertyp auf Dokumente setzen FolderType=Documents ; Ordnertyp auf Dokumente setzen
``` ```
- **`IconAreaImage`**: Setzt ein Hintergrundbild für den Ordnerbereich. - **`IconAreaImage`**: Setzt ein Hintergrundbild für den Ordnerbereich.
```ini ```ini
IconAreaImage=C:\Bilder\Hintergrund.png IconAreaImage=C:\Bilder\Hintergrund.png
``` ```
### Optionen in der `[Icon]`-Sektion ### Optionen in der `[Icon]`-Sektion
- **`IconFile`**: Der Pfad zu einer Datei, die das Ordnersymbol enthält (z. B. `.ico`, `.dll`, `.exe`). - **`IconFile`**: Der Pfad zu einer Datei, die das Ordnersymbol enthält (z. B. `.ico`, `.dll`, `.exe`).
```ini ```ini
IconFile=C:\Windows\System32\shell32.dll IconFile=C:\Windows\System32\shell32.dll
``` ```
- **`IconIndex`**: Der Index des Symbols in der Datei, wenn mehrere Symbole in einer Datei vorhanden sind. - **`IconIndex`**: Der Index des Symbols in der Datei, wenn mehrere Symbole in einer Datei vorhanden sind.
```ini ```ini
IconIndex=5 IconIndex=5
``` ```
### Optionen in der `[LocalizedFileNames]`-Sektion ### Optionen in der `[LocalizedFileNames]`-Sektion
- **`@`**: Erlaubt die Anzeige von Ordnernamen in verschiedenen Sprachen. - **`@`**: Erlaubt die Anzeige von Ordnernamen in verschiedenen Sprachen.
```ini ```ini
[LocalizedFileNames] [LocalizedFileNames]
@="Projektordner" @="Projektordner"
``` ```
### Optionen in der `[ShellClassInfo]`-Sektion ### Optionen in der `[ShellClassInfo]`-Sektion
- **`NoSharing`**: Verhindert die Freigabe des Ordners über das Netzwerk. - **`NoSharing`**: Verhindert die Freigabe des Ordners über das Netzwerk.
```ini ```ini
NoSharing=1 ; Verhindert die Netzwerkfreigabe NoSharing=1 ; Verhindert die Netzwerkfreigabe
``` ```
- **`ConfirmFileOp`**: Steuert, ob eine Bestätigung beim Kopieren von Dateien erforderlich ist. - **`ConfirmFileOp`**: Steuert, ob eine Bestätigung beim Kopieren von Dateien erforderlich ist.
```ini ```ini
ConfirmFileOp=0 ; Keine Bestätigung erforderlich ConfirmFileOp=0 ; Keine Bestätigung erforderlich
``` ```
- **`InfoTip`**: Eine zusätzliche Option zur Festlegung eines Tooltips. - **`InfoTip`**: Eine zusätzliche Option zur Festlegung eines Tooltips.
```ini ```ini
InfoTip=Dieser Ordner enthält Projektdateien. InfoTip=Dieser Ordner enthält Projektdateien.
``` ```
- **`IconFile` und `IconIndex`**: Wiederholung der Optionen zur Festlegung des Ordnersymbols. - **`IconFile` und `IconIndex`**: Wiederholung der Optionen zur Festlegung des Ordnersymbols.
```ini ```ini
IconFile=C:\Windows\System32\shell32.dll IconFile=C:\Windows\System32\shell32.dll
IconIndex=5 IconIndex=5
``` ```
## Kommentare in der `desktop.ini` ## Kommentare in der `desktop.ini`
In der `desktop.ini`-Datei können **Kommentare** durch das Hinzufügen eines **Semikolons (`;`)** am Anfang einer Zeile eingefügt werden. Alles, was nach einem Semikolon in einer Zeile steht, wird von Windows ignoriert und dient lediglich der Dokumentation. In der `desktop.ini`-Datei können **Kommentare** durch das Hinzufügen eines **Semikolons (`;`)** am Anfang einer Zeile eingefügt werden. Alles, was nach einem Semikolon in einer Zeile steht, wird von Windows ignoriert und dient lediglich der Dokumentation.
Beispiel: Beispiel:
```ini ```ini
; Dies ist ein Kommentar ; Dies ist ein Kommentar
[.ShellClassInfo] [.ShellClassInfo]
IconFile=C:\Windows\System32\shell32.dll IconFile=C:\Windows\System32\shell32.dll
IconIndex=23 IconIndex=23
``` ```
## Die Bedeutung von Attributen und Rechten der `desktop.ini` ## Die Bedeutung von Attributen und Rechten der `desktop.ini`
Die `desktop.ini`-Datei muss bestimmte **Dateiattribute** besitzen, damit sie korrekt funktioniert: Die `desktop.ini`-Datei muss bestimmte **Dateiattribute** besitzen, damit sie korrekt funktioniert:
- **Schreibgeschützt (`+r`)**: Verhindert, dass die Datei überschrieben wird. - **Schreibgeschützt (`+r`)**: Verhindert, dass die Datei überschrieben wird.
- **Versteckt (`+h`)**: Stellt sicher, dass die Datei im Windows Explorer nicht angezeigt wird. - **Versteckt (`+h`)**: Stellt sicher, dass die Datei im Windows Explorer nicht angezeigt wird.
- **System (`+s`)**: Kennzeichnet die Datei als Systemdatei, sodass Windows sie als Konfigurationsdatei erkennt. - **System (`+s`)**: Kennzeichnet die Datei als Systemdatei, sodass Windows sie als Konfigurationsdatei erkennt.
Die `desktop.ini`-Datei sollte auch die entsprechenden **Dateisystemrechte** haben, um sicherzustellen, dass sie nicht versehentlich gelöscht oder verändert wird. Die `desktop.ini`-Datei sollte auch die entsprechenden **Dateisystemrechte** haben, um sicherzustellen, dass sie nicht versehentlich gelöscht oder verändert wird.
## Rechte für die `desktop.ini` unter Windows setzen ## Rechte für die `desktop.ini` unter Windows setzen
Damit die `desktop.ini`-Datei korrekt funktioniert, müssen unter Windows bestimmte **Dateirechte und Attribute** gesetzt werden: Damit die `desktop.ini`-Datei korrekt funktioniert, müssen unter Windows bestimmte **Dateirechte und Attribute** gesetzt werden:
- **Schreibschutz setzen**: Um zu verhindern, dass die Datei überschrieben wird, kann das Schreibschutz-Attribut aktiviert werden. Dies kann über die Eingabeaufforderung mit dem Befehl `attrib +r desktop.ini` erreicht werden. - **Schreibschutz setzen**: Um zu verhindern, dass die Datei überschrieben wird, kann das Schreibschutz-Attribut aktiviert werden. Dies kann über die Eingabeaufforderung mit dem Befehl `attrib +r desktop.ini` erreicht werden.
- **Versteckt setzen**: Damit die Datei im Explorer nicht angezeigt wird, muss das versteckte Attribut gesetzt werden. Dies kann mit `attrib +h desktop.ini` erfolgen. - **Versteckt setzen**: Damit die Datei im Explorer nicht angezeigt wird, muss das versteckte Attribut gesetzt werden. Dies kann mit `attrib +h desktop.ini` erfolgen.
- **Systemdateiattribut setzen**: Um die Datei als Systemdatei zu kennzeichnen, sodass Windows sie korrekt als Konfigurationsdatei behandelt, muss das Systemattribut gesetzt werden. Verwenden Sie dazu `attrib +s desktop.ini`. - **Systemdateiattribut setzen**: Um die Datei als Systemdatei zu kennzeichnen, sodass Windows sie korrekt als Konfigurationsdatei behandelt, muss das Systemattribut gesetzt werden. Verwenden Sie dazu `attrib +s desktop.ini`.
Die richtigen Attribute können alle auf einmal gesetzt werden, indem Sie den folgenden Befehl verwenden: Die richtigen Attribute können alle auf einmal gesetzt werden, indem Sie den folgenden Befehl verwenden:
```cmd ```cmd
attrib +r +h +s desktop.ini attrib +r +h +s desktop.ini
``` ```
## Verwendung der `desktop.ini` auf NAS-Laufwerken ## Verwendung der `desktop.ini` auf NAS-Laufwerken
Die `desktop.ini`-Datei kann auch auf **NAS-Laufwerken** verwendet werden, solange das Laufwerk ein **Windows-kompatibles Dateisystem** wie **NTFS** verwendet. Es gibt jedoch einige wichtige Aspekte zu beachten: Die `desktop.ini`-Datei kann auch auf **NAS-Laufwerken** verwendet werden, solange das Laufwerk ein **Windows-kompatibles Dateisystem** wie **NTFS** verwendet. Es gibt jedoch einige wichtige Aspekte zu beachten:
- Das NAS muss ein unterstütztes Dateisystem verwenden. - Das NAS muss ein unterstütztes Dateisystem verwenden.
- Die Berechtigungen für die Datei und die Ordnersichtbarkeit müssen so konfiguriert werden, dass Windows sie korrekt lesen kann. - Die Berechtigungen für die Datei und die Ordnersichtbarkeit müssen so konfiguriert werden, dass Windows sie korrekt lesen kann.
## Fazit ## Fazit
Die `desktop.ini`-Datei ist ein mächtiges Werkzeug zur Anpassung von Ordnern in Windows. Sie ermöglicht es, das Aussehen und Verhalten von Ordnern zu verändern, ohne zusätzliche Software zu benötigen. Durch die Verwendung von Kommentaren und Attributen können Benutzer ihre Ordnerspezifikationen einfach und effektiv anpassen. Ob auf lokalen Laufwerken oder NAS-Systemen die `desktop.ini` bleibt eine vielseitige Lösung für die Ordneranpassung in Windows. Die `desktop.ini`-Datei ist ein mächtiges Werkzeug zur Anpassung von Ordnern in Windows. Sie ermöglicht es, das Aussehen und Verhalten von Ordnern zu verändern, ohne zusätzliche Software zu benötigen. Durch die Verwendung von Kommentaren und Attributen können Benutzer ihre Ordnerspezifikationen einfach und effektiv anpassen. Ob auf lokalen Laufwerken oder NAS-Systemen die `desktop.ini` bleibt eine vielseitige Lösung für die Ordneranpassung in Windows.

1122
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +1,24 @@
{ {
"name": "tools", "name": "tools",
"version": "1.0.0", "version": "1.0.0",
"type": "module", "type": "module",
"bin": { "bin": {
"link-collector": "./dist/index.js" "link-collector": "./dist/index.js"
}, },
"scripts": { "scripts": {
"build": "tsc", "build": "tsc",
"postbuild": "node tools/dist/fscopy.js -s tools/dist/collector/link_collector.js -t tools/collector/link_collector.js && npm run clean", "postbuild": "node tools/dist/fscopy.js -s tools/dist/collector/link_collector.js -t tools/collector/link_collector.js && npm run clean",
"scan": "node tools/collector/link_collector.js", "scan": "node tools/collector/link_collector.js",
"clean": "node ./tools/dist/fsdel.js ./tools/dist/collector/link_collector.js" "clean": "node ./tools/dist/fsdel.js ./tools/dist/collector/link_collector.js"
}, },
"dependencies": { "dependencies": {
"fs": "^0.0.1-security", "fs": "^0.0.1-security",
"path": "^0.12.7", "path": "^0.12.7",
"process": "^0.11.10", "process": "^0.11.10",
"typescript": "^5.8.3" "typescript": "^5.8.3"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.15.29", "@types/node": "^22.15.29",
"esbuild": "^0.25.5" "esbuild": "^0.25.5"
} }
} }

View File

@ -1,29 +1,31 @@
@echo off @echo off
REM ------------------------------------------------------------ REM ------------------------------------------------------------
REM Python-Wrapper für ein definiertes Skript mit Parametern REM Python-Wrapper für ein definiertes Skript mit Parametern
REM Führt ein festgelegtes Python-Skript aus und prüft, ob Python installiert ist REM Führt ein festgelegtes Python-Skript aus und prüft, ob Python installiert ist
REM ------------------------------------------------------------ REM
REM Wird durch (./tools/collector/link_collector.py) und `npm run scan` abgeloest!
REM ==== KONFIGURATION ===== REM ------------------------------------------------------------
set SCRIPT=tools\collector\link_collector.py
set PYTHON=python REM ==== KONFIGURATION =====
REM ======================== set SCRIPT=tools\collector\link_collector.py
set PYTHON=python
chcp 65001 >nul REM ========================
where %PYTHON% >nul 2>&1 chcp 65001 >nul
if errorlevel 1 (
echo. where %PYTHON% >nul 2>&1
echo ❌ Python wurde nicht gefunden. if errorlevel 1 (
echo. echo.
echo Bitte installiere Python von: echo ❌ Python wurde nicht gefunden.
echo https://www.python.org/downloads/windows/ echo.
echo. echo Bitte installiere Python von:
echo Alternativ: Stelle sicher, dass python.exe im PATH ist. echo https://www.python.org/downloads/windows/
pause echo.
exit /b 1 echo Alternativ: Stelle sicher, dass python.exe im PATH ist.
) pause
exit /b 1
REM Skript ausführen mit allen übergebenen Parametern )
%PYTHON% %SCRIPT% %*
pause REM Skript ausführen mit allen übergebenen Parametern
%PYTHON% %SCRIPT% %*
pause

View File

@ -1,16 +1,16 @@
{ {
// Verzeichnis relativ zum Script, das durchsucht wird // Verzeichnis relativ zum Script, das durchsucht wird
"root_dirs": [ "root_dirs": [
"dokus" "dokus"
], ],
// Nur Dateien mit dieser Endung (wird erweitert) // Nur Dateien mit dieser Endung (wird erweitert)
"extensions": [".md"], "extensions": [".md"],
// Zielpfad für die Linkausgabe (Markdown-Datei) // Zielpfad für die Linkausgabe (Markdown-Datei)
"output_file": "README.md", "output_file": "README.md",
// Optional: Log für bereits verarbeitete Dateien. Dateien die dort // Optional: Log für bereits verarbeitete Dateien. Dateien die dort
// enthalten sind, werden nicht nochmals verabeitet. // enthalten sind, werden nicht nochmals verabeitet.
"processed_log": "processed.log" "processed_log": "processed.log"
} }

View File

@ -57,19 +57,19 @@ class ArgParser {
return result; return result;
} }
static showHelp() { static showHelp() {
console.log(` console.log(`
(C) 2025 - Adam Skotarczak (ionivation.com) (C) 2025 - Adam Skotarczak (ionivation.com)
🛈 Tool das Verzeichnisse nach Markdown-Dateien durchsucht und diese an eine definierte Liste anhängt als Markdown-Link. 🛈 Tool das Verzeichnisse nach Markdown-Dateien durchsucht und diese an eine definierte Liste anhängt als Markdown-Link.
Verwendung: ts-node link_collector.ts [OPTIONEN] Verwendung: ts-node link_collector.ts [OPTIONEN]
-s, --scan Kommagetrennte Liste von Verzeichnissen zum Durchsuchen (relativ zum Aufrufpfad) -s, --scan Kommagetrennte Liste von Verzeichnissen zum Durchsuchen (relativ zum Aufrufpfad)
-x, --ignore Kommagetrennte Liste von Verzeichnissen, die ignoriert werden sollen -x, --ignore Kommagetrennte Liste von Verzeichnissen, die ignoriert werden sollen
--reset Löscht das Logfile 'processed.log' und beendet sich --reset Löscht das Logfile 'processed.log' und beendet sich
-h, --hilfe Zeigt diese Hilfe -h, --hilfe Zeigt diese Hilfe
Beispiel: Beispiel:
ts-node link_collector.ts -s docs,notes -x "docs/alt" ts-node link_collector.ts -s docs,notes -x "docs/alt"
`); `);
} }
} }

View File

@ -1,164 +1,164 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os import os
import sys import sys
import json import json
from pathlib import Path from pathlib import Path
# Gibt das Verzeichnis zurück, in dem dieses Skript liegt # Gibt das Verzeichnis zurück, in dem dieses Skript liegt
def script_dir(): def script_dir():
return Path(__file__).parent.resolve() return Path(__file__).parent.resolve()
# Lädt die JSONC-Konfiguration (Kommentare via // werden ignoriert) # Lädt die JSONC-Konfiguration (Kommentare via // werden ignoriert)
def load_config(filename="config.jsonc"): def load_config(filename="config.jsonc"):
config_path = script_dir() / filename config_path = script_dir() / filename
if not config_path.exists(): if not config_path.exists():
print(" ⚠ Konfigurationsdatei nicht gefunden:", config_path) print(" ⚠ Konfigurationsdatei nicht gefunden:", config_path)
sys.exit(1) sys.exit(1)
with open(config_path, encoding="utf-8") as f: with open(config_path, encoding="utf-8") as f:
# Entfernt //-Kommentare vor dem Parsen # Entfernt //-Kommentare vor dem Parsen
return json.loads("".join(line for line in f if not line.strip().startswith("//"))) return json.loads("".join(line for line in f if not line.strip().startswith("//")))
# Parsen der Kommandozeilenargumente # Parsen der Kommandozeilenargumente
def parse_args(): def parse_args():
args = sys.argv[1:] args = sys.argv[1:]
parsed = { parsed = {
"scan": None, # Verzeichnisse zum Scannen (List[str]) "scan": None, # Verzeichnisse zum Scannen (List[str])
"ignore": [], # Verzeichnisse, die ignoriert werden sollen (List[str]) "ignore": [], # Verzeichnisse, die ignoriert werden sollen (List[str])
"reset": False, # Setzt das Logfile zurück "reset": False, # Setzt das Logfile zurück
"hilfe": False, # Zeigt die Hilfe an "hilfe": False, # Zeigt die Hilfe an
} }
# Argumente durchgehen und zuweisen # Argumente durchgehen und zuweisen
while args: while args:
arg = args.pop(0) arg = args.pop(0)
if arg in ("-h", "--hilfe"): if arg in ("-h", "--hilfe"):
parsed["hilfe"] = True parsed["hilfe"] = True
elif arg == "--reset": elif arg == "--reset":
parsed["reset"] = True parsed["reset"] = True
elif arg in ("-s", "--scan") and args: elif arg in ("-s", "--scan") and args:
parsed["scan"] = [entry.strip() for entry in args.pop(0).split(",") if entry.strip()] parsed["scan"] = [entry.strip() for entry in args.pop(0).split(",") if entry.strip()]
elif arg in ("-x", "--ignore") and args: elif arg in ("-x", "--ignore") and args:
parsed["ignore"] = [entry.strip() for entry in args.pop(0).split(",") if entry.strip()] parsed["ignore"] = [entry.strip() for entry in args.pop(0).split(",") if entry.strip()]
else: else:
print(f" ⚠ Unbekannter Parameter: {arg}") print(f" ⚠ Unbekannter Parameter: {arg}")
parsed["hilfe"] = True parsed["hilfe"] = True
break break
return parsed return parsed
# Ausgabe der Hilfetexte für CLI-Nutzer # Ausgabe der Hilfetexte für CLI-Nutzer
def show_help(): def show_help():
print(""" print("""
(C) 2025 - Adam Skotarczak (ionivation.com) (C) 2025 - Adam Skotarczak (ionivation.com)
🛈 Tool das Verzeichnisse nach Markdown-Dateien durchsucht und diese an eine definierte Liste anhängt als Markdown-Link. 🛈 Tool das Verzeichnisse nach Markdown-Dateien durchsucht und diese an eine definierte Liste anhängt als Markdown-Link.
Verwendung: python3 link_collector.py [OPTIONEN] Verwendung: python3 link_collector.py [OPTIONEN]
-s, --scan Kommagetrennte Liste von Verzeichnissen zum Durchsuchen (relativ zum Aufrufpfad) -s, --scan Kommagetrennte Liste von Verzeichnissen zum Durchsuchen (relativ zum Aufrufpfad)
-x, --ignore Kommagetrennte Liste von Verzeichnissen, die ignoriert werden sollen -x, --ignore Kommagetrennte Liste von Verzeichnissen, die ignoriert werden sollen
--reset Löscht das Logfile 'processed.log' und beendet sich --reset Löscht das Logfile 'processed.log' und beendet sich
-h, --hilfe Zeigt diese Hilfe -h, --hilfe Zeigt diese Hilfe
Beispiel: Beispiel:
python3 link_collector.py -s docs,notes -x "docs/alt" python3 link_collector.py -s docs,notes -x "docs/alt"
""") """)
# Generator: Findet Markdown-Dateien (rekursiv), ignoriert dabei definierte Pfade # Generator: Findet Markdown-Dateien (rekursiv), ignoriert dabei definierte Pfade
def find_md_files(root_dirs, ignore_dirs, extensions): def find_md_files(root_dirs, ignore_dirs, extensions):
for root in root_dirs: for root in root_dirs:
for dirpath, _, filenames in os.walk(root): for dirpath, _, filenames in os.walk(root):
# Ignorierpfade überspringen # Ignorierpfade überspringen
if any(str(Path(dirpath)).startswith(str(ignored)) for ignored in ignore_dirs): if any(str(Path(dirpath)).startswith(str(ignored)) for ignored in ignore_dirs):
continue continue
for fname in filenames: for fname in filenames:
if any(fname.endswith(ext) for ext in extensions): if any(fname.endswith(ext) for ext in extensions):
yield Path(dirpath) / fname yield Path(dirpath) / fname
# Extrahiert den ersten Markdown-Titel (# ...) als Linktext # Extrahiert den ersten Markdown-Titel (# ...) als Linktext
def extract_title(filepath): def extract_title(filepath):
try: try:
with open(filepath, encoding="utf-8") as f: with open(filepath, encoding="utf-8") as f:
for line in f: for line in f:
if line.strip().startswith("#"): if line.strip().startswith("#"):
return line.strip("# ").strip() return line.strip("# ").strip()
except Exception as e: except Exception as e:
print(f"⚠ Fehler beim Lesen von {filepath}: {e}") print(f"⚠ Fehler beim Lesen von {filepath}: {e}")
# Fallback: Dateiname ohne Endung # Fallback: Dateiname ohne Endung
return filepath.stem return filepath.stem
# Liest bereits verarbeitete Dateien aus dem Log (Pfadangaben im POSIX-Format) # Liest bereits verarbeitete Dateien aus dem Log (Pfadangaben im POSIX-Format)
def load_processed(logfile): def load_processed(logfile):
if not logfile.exists(): if not logfile.exists():
return set() return set()
with open(logfile, encoding="utf-8") as f: with open(logfile, encoding="utf-8") as f:
# Vereinheitlichung auf POSIX-Konvention # Vereinheitlichung auf POSIX-Konvention
return set(Path(line.strip()).as_posix() for line in f) return set(Path(line.strip()).as_posix() for line in f)
# Hängt neue Markdown-Links ans Output-Dokument an # Hängt neue Markdown-Links ans Output-Dokument an
def append_to_output(output_path, links): def append_to_output(output_path, links):
with open(output_path, "a", encoding="utf-8") as f: with open(output_path, "a", encoding="utf-8") as f:
for line in links: for line in links:
f.write(line + "\n") f.write(line + "\n")
# Ergänzt das Logfile um neu verarbeitete Dateien (POSIX-Format) # Ergänzt das Logfile um neu verarbeitete Dateien (POSIX-Format)
def update_processed(log_path, new_paths): def update_processed(log_path, new_paths):
with open(log_path, "a", encoding="utf-8") as f: with open(log_path, "a", encoding="utf-8") as f:
for path in new_paths: for path in new_paths:
f.write(path.as_posix() + "\n") f.write(path.as_posix() + "\n")
# Hauptfunktion mit gesamtem Ablauf # Hauptfunktion mit gesamtem Ablauf
def main(): def main():
config = load_config() config = load_config()
args = parse_args() args = parse_args()
if args["hilfe"]: if args["hilfe"]:
show_help() show_help()
return return
log_path = script_dir() / config.get("processed_log", "processed.log") log_path = script_dir() / config.get("processed_log", "processed.log")
# Optionaler Reset des Logs # Optionaler Reset des Logs
if args["reset"]: if args["reset"]:
if log_path.exists(): if log_path.exists():
log_path.unlink() log_path.unlink()
print("🧹 Logfile gelöscht:", log_path) print("🧹 Logfile gelöscht:", log_path)
else: else:
print(" Logfile existierte nicht:", log_path) print(" Logfile existierte nicht:", log_path)
return return
cwd = Path.cwd() cwd = Path.cwd()
output_file = cwd / config.get("output_file", "output.md") output_file = cwd / config.get("output_file", "output.md")
# Verzeichnisse aus CLI oder Konfiguration # Verzeichnisse aus CLI oder Konfiguration
root_dirs = args["scan"] or config.get("root_dirs", []) root_dirs = args["scan"] or config.get("root_dirs", [])
root_dirs = [Path(d).resolve() for d in root_dirs if d.strip()] root_dirs = [Path(d).resolve() for d in root_dirs if d.strip()]
ignore_dirs = [Path(x).resolve() for x in args["ignore"]] ignore_dirs = [Path(x).resolve() for x in args["ignore"]]
extensions = config.get("extensions", [".md"]) extensions = config.get("extensions", [".md"])
processed = load_processed(log_path) processed = load_processed(log_path)
new_links = [] new_links = []
new_processed = [] new_processed = []
# Dateien durchsuchen und neue Markdown-Dateien verlinken # Dateien durchsuchen und neue Markdown-Dateien verlinken
for md_file in find_md_files(root_dirs, ignore_dirs, extensions): for md_file in find_md_files(root_dirs, ignore_dirs, extensions):
if md_file.resolve() == output_file.resolve(): if md_file.resolve() == output_file.resolve():
continue # nicht sich selbst verlinken continue # nicht sich selbst verlinken
rel_path = md_file.relative_to(cwd) rel_path = md_file.relative_to(cwd)
rel_path_posix = rel_path.as_posix() rel_path_posix = rel_path.as_posix()
if rel_path_posix in processed: if rel_path_posix in processed:
continue # bereits im Logfile continue # bereits im Logfile
title = extract_title(md_file) title = extract_title(md_file)
new_links.append(f"- [{title}]({rel_path_posix})") new_links.append(f"- [{title}]({rel_path_posix})")
new_processed.append(rel_path) new_processed.append(rel_path)
# Ergebnisse schreiben # Ergebnisse schreiben
if new_links: if new_links:
append_to_output(output_file, new_links) append_to_output(output_file, new_links)
update_processed(log_path, new_processed) update_processed(log_path, new_processed)
print(f"{len(new_links)} neue Links hinzugefügt.") print(f"{len(new_links)} neue Links hinzugefügt.")
else: else:
print(" Keine neuen Dateien gefunden.") print(" Keine neuen Dateien gefunden.")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -1,13 +1,14 @@
dokus/helix__editor_einfuehrung_de.md dokus/helix__editor_einfuehrung_de.md
dokus/windows/desktop_ini.md dokus/windows/desktop_ini.md
dokus/webserver/nginx-proxy-manager-setup.md
dokus/rust/rust-offline-installation.md
dokus/rust/rust-toolchain-msvc.md
dokus/plesk/lets-encrypt-plesk.md
dokus/plesk/plesk-benutzer-schon-vorhanden.md dokus/plesk/plesk-benutzer-schon-vorhanden.md
dokus/mechanik/gewindetabellen.md dokus/mechanik/gewindetabellen.md
dokus/js-ts/js-ts-dialekte.md dokus/js-ts/js-ts-dialekte.md
dokus/git/git-remote-branch.md dokus/git/git-remote-branch.md
dokus/git/git-ssh-remote.md dokus/git/git-ssh-remote.md
dokus/git/git-submodule-leitfaden.md
dokus/git/git.md dokus/git/git.md
dokus/asciidoc/asciidoctor-theme-bug-workaround.md dokus/asciidoc/asciidoctor-theme-bug-workaround.md
dokus/apache-plesk/lets-encrypt-plesk.md
dokus/git/git-submodule-leitfaden.md
dokus/rust/rust-toolchain-msvc.md
dokus/rust/rust-offline-installation.md

View File

@ -1,16 +1,16 @@
{ {
// Verzeichnis relativ zum Script, das durchsucht wird // Verzeichnis relativ zum Script, das durchsucht wird
"root_dirs": [ "root_dirs": [
"dokus" "dokus"
], ],
// Nur Dateien mit dieser Endung (wird erweitert) // Nur Dateien mit dieser Endung (wird erweitert)
"extensions": [".md"], "extensions": [".md"],
// Zielpfad für die Linkausgabe (Markdown-Datei) // Zielpfad für die Linkausgabe (Markdown-Datei)
"output_file": "README.md", "output_file": "README.md",
// Optional: Log für bereits verarbeitete Dateien. Dateien die dort // Optional: Log für bereits verarbeitete Dateien. Dateien die dort
// enthalten sind, werden nicht nochmals verabeitet. // enthalten sind, werden nicht nochmals verabeitet.
"processed_log": "processed.log" "processed_log": "processed.log"
} }

View File

@ -1,225 +1,225 @@
#!/usr/bin/env node #!/usr/bin/env node
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import * as path from 'node:path'; import * as path from 'node:path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path'; import { dirname } from 'node:path';
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename); const __dirname = dirname(__filename);
type Config = { type Config = {
root_dirs?: string[]; root_dirs?: string[];
output_file?: string; output_file?: string;
processed_log?: string; processed_log?: string;
extensions?: string[]; extensions?: string[];
}; };
type Args = { type Args = {
scan: string[] | null; scan: string[] | null;
ignore: string[]; ignore: string[];
reset: boolean; reset: boolean;
hilfe: boolean; hilfe: boolean;
}; };
class ScriptInfo { class ScriptInfo {
static dir(): string { static dir(): string {
return path.dirname(__filename); return path.dirname(__filename);
} }
static cwd(): string { static cwd(): string {
return process.cwd(); return process.cwd();
} }
} }
class ConfigLoader { class ConfigLoader {
static load(filename = 'config.jsonc'): Config { static load(filename = 'config.jsonc'): Config {
const configPath = path.join(ScriptInfo.dir(), filename); const configPath = path.join(ScriptInfo.dir(), filename);
if (!fs.existsSync(configPath)) { if (!fs.existsSync(configPath)) {
console.error(` ⚠ Konfigurationsdatei nicht gefunden: ${configPath}`); console.error(` ⚠ Konfigurationsdatei nicht gefunden: ${configPath}`);
process.exit(1); process.exit(1);
} }
const raw = fs.readFileSync(configPath, 'utf8'); const raw = fs.readFileSync(configPath, 'utf8');
const clean = raw const clean = raw
.split('\n') .split('\n')
.filter(line => !line.trim().startsWith('//')) .filter(line => !line.trim().startsWith('//'))
.join(''); .join('');
return JSON.parse(clean); return JSON.parse(clean);
} }
} }
class ArgParser { class ArgParser {
static parse(): Args { static parse(): Args {
const argv = process.argv.slice(2); const argv = process.argv.slice(2);
const result: Args = { scan: null, ignore: [], reset: false, hilfe: false }; const result: Args = { scan: null, ignore: [], reset: false, hilfe: false };
while (argv.length) { while (argv.length) {
const arg = argv.shift(); const arg = argv.shift();
if (!arg) break; if (!arg) break;
if (arg === '-h' || arg === '--hilfe') { if (arg === '-h' || arg === '--hilfe') {
result.hilfe = true; result.hilfe = true;
} else if (arg === '--reset') { } else if (arg === '--reset') {
result.reset = true; result.reset = true;
} else if ((arg === '-s' || arg === '--scan') && argv.length) { } else if ((arg === '-s' || arg === '--scan') && argv.length) {
result.scan = argv.shift()!.split(',').map(x => x.trim()).filter(Boolean); result.scan = argv.shift()!.split(',').map(x => x.trim()).filter(Boolean);
} else if ((arg === '-x' || arg === '--ignore') && argv.length) { } else if ((arg === '-x' || arg === '--ignore') && argv.length) {
result.ignore = argv.shift()!.split(',').map(x => x.trim()).filter(Boolean); result.ignore = argv.shift()!.split(',').map(x => x.trim()).filter(Boolean);
} else { } else {
console.warn(` ⚠ Unbekannter Parameter: ${arg}`); console.warn(` ⚠ Unbekannter Parameter: ${arg}`);
result.hilfe = true; result.hilfe = true;
break; break;
} }
} }
return result; return result;
} }
static showHelp(): void { static showHelp(): void {
console.log(` console.log(`
(C) 2025 - Adam Skotarczak (ionivation.com) (C) 2025 - Adam Skotarczak (ionivation.com)
🛈 Tool das Verzeichnisse nach Markdown-Dateien durchsucht und diese an eine definierte Liste anhängt als Markdown-Link. 🛈 Tool das Verzeichnisse nach Markdown-Dateien durchsucht und diese an eine definierte Liste anhängt als Markdown-Link.
Verwendung: ts-node link_collector.ts [OPTIONEN] Verwendung: ts-node link_collector.ts [OPTIONEN]
-s, --scan Kommagetrennte Liste von Verzeichnissen zum Durchsuchen (relativ zum Aufrufpfad) -s, --scan Kommagetrennte Liste von Verzeichnissen zum Durchsuchen (relativ zum Aufrufpfad)
-x, --ignore Kommagetrennte Liste von Verzeichnissen, die ignoriert werden sollen -x, --ignore Kommagetrennte Liste von Verzeichnissen, die ignoriert werden sollen
--reset Löscht das Logfile 'processed.log' und beendet sich --reset Löscht das Logfile 'processed.log' und beendet sich
-h, --hilfe Zeigt diese Hilfe -h, --hilfe Zeigt diese Hilfe
Beispiel: Beispiel:
ts-node link_collector.ts -s docs,notes -x "docs/alt" ts-node link_collector.ts -s docs,notes -x "docs/alt"
`); `);
} }
} }
class FileScanner { class FileScanner {
static *find(rootDirs: string[], ignoreDirs: string[], extensions: string[]): Generator<string> { static *find(rootDirs: string[], ignoreDirs: string[], extensions: string[]): Generator<string> {
for (const root of rootDirs) { for (const root of rootDirs) {
const absRoot = path.resolve(root); const absRoot = path.resolve(root);
const stack = [absRoot]; const stack = [absRoot];
while (stack.length) { while (stack.length) {
const current = stack.pop()!; const current = stack.pop()!;
const rel = path.relative(ScriptInfo.cwd(), current).replace(/\\/g, '/'); const rel = path.relative(ScriptInfo.cwd(), current).replace(/\\/g, '/');
if (ignoreDirs.some(ignored => rel.startsWith(ignored))) continue; if (ignoreDirs.some(ignored => rel.startsWith(ignored))) continue;
const entries = fs.readdirSync(current, { withFileTypes: true }); const entries = fs.readdirSync(current, { withFileTypes: true });
for (const entry of entries) { for (const entry of entries) {
const fullPath = path.join(current, entry.name); const fullPath = path.join(current, entry.name);
if (entry.isDirectory()) { if (entry.isDirectory()) {
stack.push(fullPath); stack.push(fullPath);
} else if (extensions.some(ext => entry.name.endsWith(ext))) { } else if (extensions.some(ext => entry.name.endsWith(ext))) {
yield fullPath; yield fullPath;
} }
} }
} }
} }
} }
} }
class TitleExtractor { class TitleExtractor {
static extract(filepath: string): string { static extract(filepath: string): string {
try { try {
const content = fs.readFileSync(filepath, 'utf8'); const content = fs.readFileSync(filepath, 'utf8');
for (const line of content.split('\n')) { for (const line of content.split('\n')) {
if (line.trim().startsWith('#')) { if (line.trim().startsWith('#')) {
return line.replace(/^#+/, '').trim(); return line.replace(/^#+/, '').trim();
} }
} }
} catch (e) { } catch (e) {
console.error(`⚠ Fehler beim Lesen von ${filepath}: ${e}`); console.error(`⚠ Fehler beim Lesen von ${filepath}: ${e}`);
} }
return path.basename(filepath, path.extname(filepath)); return path.basename(filepath, path.extname(filepath));
} }
} }
class ProcessedLog { class ProcessedLog {
private readonly logPath: string; private readonly logPath: string;
private entries: Set<string>; private entries: Set<string>;
constructor(filename: string) { constructor(filename: string) {
this.logPath = path.join(ScriptInfo.dir(), filename); this.logPath = path.join(ScriptInfo.dir(), filename);
this.entries = new Set<string>(); this.entries = new Set<string>();
this.load(); this.load();
} }
private load() { private load() {
if (!fs.existsSync(this.logPath)) return; if (!fs.existsSync(this.logPath)) return;
const lines = fs.readFileSync(this.logPath, 'utf8').split('\n').map(x => x.trim()).filter(Boolean); const lines = fs.readFileSync(this.logPath, 'utf8').split('\n').map(x => x.trim()).filter(Boolean);
this.entries = new Set(lines.map(p => p.replace(/\\/g, '/'))); this.entries = new Set(lines.map(p => p.replace(/\\/g, '/')));
} }
has(posixPath: string): boolean { has(posixPath: string): boolean {
return this.entries.has(posixPath); return this.entries.has(posixPath);
} }
update(newPaths: string[]): void { update(newPaths: string[]): void {
const content = newPaths.map(p => p.replace(/\\/g, '/')).join('\n') + '\n'; const content = newPaths.map(p => p.replace(/\\/g, '/')).join('\n') + '\n';
fs.appendFileSync(this.logPath, content, 'utf8'); fs.appendFileSync(this.logPath, content, 'utf8');
} }
reset(): void { reset(): void {
if (fs.existsSync(this.logPath)) { if (fs.existsSync(this.logPath)) {
fs.unlinkSync(this.logPath); fs.unlinkSync(this.logPath);
console.log('🧹 Logfile gelöscht:', this.logPath); console.log('🧹 Logfile gelöscht:', this.logPath);
} else { } else {
console.log(' Logfile existierte nicht:', this.logPath); console.log(' Logfile existierte nicht:', this.logPath);
} }
} }
} }
class MarkdownAppender { class MarkdownAppender {
static append(outputFile: string, links: string[]): void { static append(outputFile: string, links: string[]): void {
const content = links.join('\n') + '\n'; const content = links.join('\n') + '\n';
fs.appendFileSync(outputFile, content, 'utf8'); fs.appendFileSync(outputFile, content, 'utf8');
} }
} }
// Einstiegspunkt // Einstiegspunkt
function main() { function main() {
const config = ConfigLoader.load(); const config = ConfigLoader.load();
const args = ArgParser.parse(); const args = ArgParser.parse();
if (args.hilfe) { if (args.hilfe) {
ArgParser.showHelp(); ArgParser.showHelp();
return; return;
} }
const log = new ProcessedLog(config.processed_log || 'processed.log'); const log = new ProcessedLog(config.processed_log || 'processed.log');
if (args.reset) { if (args.reset) {
log.reset(); log.reset();
return; return;
} }
const cwd = ScriptInfo.cwd(); const cwd = ScriptInfo.cwd();
const outputFile = path.resolve(cwd, config.output_file || 'output.md'); const outputFile = path.resolve(cwd, config.output_file || 'output.md');
const rootDirs = (args.scan || config.root_dirs || []).map(d => path.resolve(d)); const rootDirs = (args.scan || config.root_dirs || []).map(d => path.resolve(d));
const ignoreDirs = (args.ignore || []).map(d => path.relative(cwd, path.resolve(d)).replace(/\\/g, '/')); const ignoreDirs = (args.ignore || []).map(d => path.relative(cwd, path.resolve(d)).replace(/\\/g, '/'));
const extensions = config.extensions || ['.md']; const extensions = config.extensions || ['.md'];
const newLinks: string[] = []; const newLinks: string[] = [];
const newProcessed: string[] = []; const newProcessed: string[] = [];
for (const absPath of FileScanner.find(rootDirs, ignoreDirs, extensions)) { for (const absPath of FileScanner.find(rootDirs, ignoreDirs, extensions)) {
const relPath = path.relative(cwd, absPath).replace(/\\/g, '/'); const relPath = path.relative(cwd, absPath).replace(/\\/g, '/');
if (path.resolve(absPath) === outputFile || log.has(relPath)) continue; if (path.resolve(absPath) === outputFile || log.has(relPath)) continue;
const title = TitleExtractor.extract(absPath); const title = TitleExtractor.extract(absPath);
newLinks.push(`- [${title}](${relPath})`); newLinks.push(`- [${title}](${relPath})`);
newProcessed.push(relPath); newProcessed.push(relPath);
} }
if (newLinks.length > 0) { if (newLinks.length > 0) {
MarkdownAppender.append(outputFile, newLinks); MarkdownAppender.append(outputFile, newLinks);
log.update(newProcessed); log.update(newProcessed);
console.log(`${newLinks.length} neue Links hinzugefügt.`); console.log(`${newLinks.length} neue Links hinzugefügt.`);
} else { } else {
console.log(' Keine neuen Dateien gefunden.'); console.log(' Keine neuen Dateien gefunden.');
} }
} }
main(); main();

View File

@ -1,80 +1,80 @@
#!/usr/bin/env ts-node #!/usr/bin/env ts-node
/** /**
* Robust plattformunabhängiger Dateikopierer * Robust plattformunabhängiger Dateikopierer
* Verwendung: node fscopy.ts -s <quelle> -t <ziel> * Verwendung: node fscopy.ts -s <quelle> -t <ziel>
* Optionen: -h | --help * Optionen: -h | --help
*/ */
import * as fs from "fs"; import * as fs from "fs";
import * as path from "path"; import * as path from "path";
function showHelp(): void { function showHelp(): void {
console.log(` console.log(`
Copy Files with node.js Copy Files with node.js
Verwendung: Verwendung:
node fscopy.ts -s <quelle> -q <ziel> node fscopy.ts -s <quelle> -q <ziel>
Parameter: Parameter:
-s, --source Pfad zur Quelldatei (z.B. static/.htaccess) -s, --source Pfad zur Quelldatei (z.B. static/.htaccess)
-t, --target Pfad zur Zieldatei (z.B. dist/app/.htaccess) -t, --target Pfad zur Zieldatei (z.B. dist/app/.htaccess)
-h, --help Diese Hilfe anzeigen -h, --help Diese Hilfe anzeigen
`); `);
process.exit(0); process.exit(0);
} }
function parseArgs(): { source: string; ziel: string } { function parseArgs(): { source: string; ziel: string } {
const args = process.argv.slice(2); const args = process.argv.slice(2);
let source = ""; let source = "";
let ziel = ""; let ziel = "";
for (let i = 0; i < args.length; i++) { for (let i = 0; i < args.length; i++) {
switch (args[i]) { switch (args[i]) {
case "-s": case "-s":
case "--source": case "--source":
source = args[++i]; source = args[++i];
break; break;
case "-t": case "-t":
case "--target": case "--target":
ziel = args[++i]; ziel = args[++i];
break; break;
case "-h": case "-h":
case "--help": case "--help":
showHelp(); showHelp();
break; break;
default: default:
console.error(`Unbekannter Parameter: ${args[i]}`); console.error(`Unbekannter Parameter: ${args[i]}`);
showHelp(); showHelp();
} }
} }
if (!source || !ziel) { if (!source || !ziel) {
console.error("❌ Quelle und Ziel müssen angegeben werden."); console.error("❌ Quelle und Ziel müssen angegeben werden.");
showHelp(); showHelp();
} }
return { source, ziel }; return { source, ziel };
} }
function copyFile(source: string, ziel: string): void { function copyFile(source: string, ziel: string): void {
const zielVerzeichnis = path.dirname(ziel); const zielVerzeichnis = path.dirname(ziel);
fs.mkdir(zielVerzeichnis, { recursive: true }, (mkdirErr) => { fs.mkdir(zielVerzeichnis, { recursive: true }, (mkdirErr) => {
if (mkdirErr) { if (mkdirErr) {
console.error(`❌ Zielverzeichnis konnte nicht erstellt werden: ${mkdirErr.message}`); console.error(`❌ Zielverzeichnis konnte nicht erstellt werden: ${mkdirErr.message}`);
process.exit(1); process.exit(1);
} }
fs.copyFile(source, ziel, (copyErr) => { fs.copyFile(source, ziel, (copyErr) => {
if (copyErr) { if (copyErr) {
console.error(`❌ Fehler beim Kopieren: ${copyErr.message}`); console.error(`❌ Fehler beim Kopieren: ${copyErr.message}`);
process.exit(1); process.exit(1);
} }
console.log(`✔ Datei erfolgreich kopiert: ${source}${ziel}`); console.log(`✔ Datei erfolgreich kopiert: ${source}${ziel}`);
}); });
}); });
} }
// Ausführung // Ausführung
const { source, ziel } = parseArgs(); const { source, ziel } = parseArgs();
copyFile(source, ziel); copyFile(source, ziel);

View File

@ -1,41 +1,41 @@
#!/usr/bin/env ts-node #!/usr/bin/env ts-node
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
/** /**
* Löscht eine Datei am angegebenen Pfad. * Löscht eine Datei am angegebenen Pfad.
* *
* @param filePath - Pfad zur Datei, die gelöscht werden soll * @param filePath - Pfad zur Datei, die gelöscht werden soll
*/ */
function deleteFile(filePath: string): void { function deleteFile(filePath: string): void {
const resolvedPath = path.resolve(filePath); const resolvedPath = path.resolve(filePath);
if (!fs.existsSync(resolvedPath)) { if (!fs.existsSync(resolvedPath)) {
console.error(`❌ Datei nicht gefunden: ${resolvedPath}`); console.error(`❌ Datei nicht gefunden: ${resolvedPath}`);
process.exit(1); process.exit(1);
} }
try { try {
fs.unlinkSync(resolvedPath); fs.unlinkSync(resolvedPath);
console.log(`✔ Datei gelöscht: ${resolvedPath}`); console.log(`✔ Datei gelöscht: ${resolvedPath}`);
} catch (err) { } catch (err) {
console.error(`❌ Fehler beim Löschen: ${(err as Error).message}`); console.error(`❌ Fehler beim Löschen: ${(err as Error).message}`);
process.exit(1); process.exit(1);
} }
} }
// Kommandozeilenargumente // Kommandozeilenargumente
const [, , arg] = process.argv; const [, , arg] = process.argv;
if (!arg || arg === '-h' || arg === '--help') { if (!arg || arg === '-h' || arg === '--help') {
console.log(`Verwendung: console.log(`Verwendung:
ts-node delete.ts <dateipfad> ts-node delete.ts <dateipfad>
Beispiel: Beispiel:
ts-node delete.ts ./log/output.txt`); ts-node delete.ts ./log/output.txt`);
process.exit(0); process.exit(0);
} }
// Datei löschen // Datei löschen
deleteFile(arg); deleteFile(arg);

View File

@ -1,11 +1,11 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES2020", "target": "ES2020",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "node",
"outDir": "./tools/dist", "outDir": "./tools/dist",
"rootDir": "./tools/src", "rootDir": "./tools/src",
"strict": true "strict": true
}, },
"include": ["tools/src"] "include": ["tools/src"]
} }