v0.3.0
This commit is contained in:
parent
d28fc84bae
commit
87fb37fdd5
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
.vscode/
|
||||
|
||||
node_modules/
|
||||
dist/
|
||||
.vscode/
|
||||
|
||||
node_modules/
|
||||
dist/
|
||||
|
40
CHANGELOG.md
40
CHANGELOG.md
@ -1,16 +1,24 @@
|
||||
# Changelog
|
||||
|
||||
- **25/06/15** - commit: v0.2.0
|
||||
- **Hinzugefügt:**
|
||||
- [X] git submodule erstellt
|
||||
- [X] Rust Toolchain Einrichtung
|
||||
- [X] Rust offline-installation
|
||||
|
||||
- **25/06/15** - commit: v0.1.0
|
||||
- **Hinzugefügt:**
|
||||
- [X] helix
|
||||
- [x] desktop.ini
|
||||
|
||||
---
|
||||
|
||||
- **initial commit**
|
||||
# Changelog
|
||||
|
||||
- **27/06/15** - commit: v0.3.0
|
||||
- **Hinzugefügt:**
|
||||
- [X] Nginx Proxy Manager
|
||||
|
||||
---
|
||||
|
||||
- **25/06/15** - commit: v0.2.0
|
||||
- **Hinzugefügt:**
|
||||
- [X] git submodule erstellt
|
||||
- [X] Rust Toolchain Einrichtung
|
||||
- [X] Rust offline-installation
|
||||
|
||||
---
|
||||
|
||||
- **25/06/15** - commit: v0.1.0
|
||||
- **Hinzugefügt:**
|
||||
- [X] helix
|
||||
- [x] desktop.ini
|
||||
|
||||
---
|
||||
|
||||
- **initial commit**
|
||||
|
2
LICENSE
2
LICENSE
@ -1 +1 @@
|
||||
(C) 2025 - Adam Skotarczak <adam@skotarczak.net
|
||||
(C) 2025 - Adam Skotarczak <adam@skotarczak.net
|
||||
|
353
README.md
353
README.md
@ -1,175 +1,178 @@
|
||||
# -= Admin´s Log =-
|
||||
|
||||

|
||||
|
||||
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.
|
||||
Die Artikel sind auch zur Vorbereitung für neue Artikel auf <https://www.ionivation.com> vorgesehen.
|
||||
|
||||
**origin:** <https://local.ionivation.com/realAscot/adminslog>
|
||||
|
||||
## Inhalt
|
||||
|
||||
- [-= Admin´s Log =-](#--admins-log--)
|
||||
- [Inhalt](#inhalt)
|
||||
- [Informationen](#informationen)
|
||||
- [Themen](#themen)
|
||||
- [AsciiDoc](#asciidoc)
|
||||
- [Editoren/ IDE´s](#editoren-ides)
|
||||
- [Helix](#helix)
|
||||
- [Git](#git)
|
||||
- [Markdown](#markdown)
|
||||
- [Mermaid](#mermaid)
|
||||
- [Mechanik](#mechanik)
|
||||
- [Server](#server)
|
||||
- [Plesk](#plesk)
|
||||
- [Webserver](#webserver)
|
||||
- [Windows](#windows)
|
||||
- [Programmierung](#programmierung)
|
||||
- [Rust](#rust)
|
||||
- [ts - js - node](#ts---js---node)
|
||||
- [Projektinhalt](#projektinhalt)
|
||||
- [Neue Dokumente](#neue-dokumente)
|
||||
|
||||
---
|
||||
|
||||
## Informationen
|
||||
|
||||
Unter `./tools/` befinden sich Programme/ Skripte (aktuell in Typescript und Python) die Markdown-Dateien suchen und daraus ein Verzeichnis erstellen.
|
||||
|
||||
---
|
||||
|
||||
## Themen
|
||||
|
||||
---
|
||||
|
||||
### AsciiDoc
|
||||
|
||||
- [Asciidoctor PDF: Kapitel bleibt „Chapter“ – Fehleranalyse & Workaround](dokus/asciidoc/asciidoctor-theme-bug-workaround.md)
|
||||
|
||||
---
|
||||
|
||||
### Editoren/ IDE´s
|
||||
|
||||
#### Helix
|
||||
|
||||
- [Helix Editor – Ein umfassender Einstieg für Anfänger (Deutsch)](dokus/helix__editor_einfuehrung_de.md)
|
||||
|
||||
---
|
||||
|
||||
### Git
|
||||
|
||||
- [Artikel: git](dokus/git/git.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-Submodule: Der umfassende Praxisleitfaden](dokus/git/git-submodule-leitfaden.md)
|
||||
|
||||
### Markdown
|
||||
|
||||
#### Mermaid
|
||||
|
||||
- [mermaidPockedGuide](https://local.ionivation.com/realAscot/mermaidPockedGuide) **EXTERN** 🚀
|
||||
|
||||
### Mechanik
|
||||
|
||||
- [Gewindetabellen](dokus/mechanik/gewindetabellen.md)
|
||||
|
||||
---
|
||||
|
||||
### Server
|
||||
|
||||
#### Plesk
|
||||
|
||||
- [Plesk ausgesperrt bei Rechnerwechsel](dokus/plesk/plesk-benutzer-schon-vorhanden.md)
|
||||
|
||||
#### Webserver
|
||||
|
||||
- [Let's Encrypt: Fehlerbehebung bei Challenge-Timeout unter Plesk](dokus/apache-plesk/lets-encrypt-plesk.md)
|
||||
|
||||
---
|
||||
|
||||
### Windows
|
||||
|
||||
- [Einführung in die `desktop.ini`-Datei: Verwendung und Anpassung von Ordnern in Windows](dokus/windows/desktop_ini.md)
|
||||
|
||||
---
|
||||
|
||||
### Programmierung
|
||||
|
||||
#### 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)
|
||||
|
||||
---
|
||||
|
||||
#### ts - js - node
|
||||
|
||||
- [Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration](dokus/js-ts/js-ts-dialekte.md)
|
||||
|
||||
---
|
||||
|
||||
## Projektinhalt
|
||||
|
||||
*Erstellt mit [treescanner](https://github.com/realAscot/treeScanner)*
|
||||
|
||||
```plaintext
|
||||
📁 ./
|
||||
├── 📁 dokus
|
||||
│ ├── 📁 apache-plesk
|
||||
│ │ └── 📄 lets-encrypt-plesk.md
|
||||
│ ├── 📁 asciidoc
|
||||
│ │ └── 📄 asciidoctor-theme-bug-workaround.md
|
||||
│ ├── 📁 git
|
||||
│ │ ├── 📄 git-remote-branch.md
|
||||
│ │ ├── 📄 git-ssh-remote.md
|
||||
│ │ ├── 📄 git-submodule-leitfaden.md
|
||||
│ │ └── 📄 git.md
|
||||
│ ├── 📁 js-ts
|
||||
│ │ └── 📄 js-ts-dialekte.md
|
||||
│ ├── 📁 mechanik
|
||||
│ │ └── 📄 gewindetabellen.md
|
||||
│ ├── 📁 plesk
|
||||
│ │ └── 📄 plesk-benutzer-schon-vorhanden.md
|
||||
│ ├── 📁 rust
|
||||
│ │ ├── 📄 rust-offline-installation.md
|
||||
│ │ └── 📄 rust-toolchain-msvc.md
|
||||
│ ├── 📁 windows
|
||||
│ │ └── 📄 desktop_ini.md
|
||||
│ └── 📄 helix__editor_einfuehrung_de.md
|
||||
├── 📁 media
|
||||
│ └── 📄 realAscotLogo_128x128.png
|
||||
├── 📁 tools
|
||||
│ ├── 📁 collector
|
||||
│ │ ├── 📄 config.jsonc
|
||||
│ │ ├── 📄 link_collector.js
|
||||
│ │ ├── 📄 link_collector.py
|
||||
│ │ └── 📄 processed.log
|
||||
│ ├── 📁 dist
|
||||
│ │ ├── 📁 collector
|
||||
│ │ ├── 📄 fscopy.js
|
||||
│ │ └── 📄 fsdel.js
|
||||
│ └── 📁 src
|
||||
│ ├── 📁 collector
|
||||
│ │ ├── 📄 config.jsonc.template
|
||||
│ │ └── 📄 link_collector.ts
|
||||
│ ├── 📄 fscopy.ts
|
||||
│ └── 📄 fsdel.ts
|
||||
├── 📄 .gitignore
|
||||
├── 📄 CHANGELOG.md
|
||||
├── 📄 LICENSE
|
||||
├── 📄 package-lock.json
|
||||
├── 📄 package.json
|
||||
├── 📄 README.md
|
||||
├── 📄 scan.cmd
|
||||
├── 📄 tsconfig.json
|
||||
└── 📄 VERSION
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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!
|
||||
|
||||
**NEUE EINTRÄGE AUS 'link_collector'->**
|
||||
# -= Admin´s Log =-
|
||||
|
||||

|
||||
|
||||
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.
|
||||
Die Artikel sind auch zur Vorbereitung für neue Artikel auf <https://www.ionivation.com> vorgesehen.
|
||||
|
||||
**origin:** <https://local.ionivation.com/realAscot/adminslog>
|
||||
|
||||
## Inhalt
|
||||
|
||||
- [-= Admin´s Log =-](#--admins-log--)
|
||||
- [Inhalt](#inhalt)
|
||||
- [Informationen](#informationen)
|
||||
- [Themen](#themen)
|
||||
- [AsciiDoc](#asciidoc)
|
||||
- [Editoren/ IDE´s](#editoren-ides)
|
||||
- [Helix](#helix)
|
||||
- [Git](#git)
|
||||
- [Markdown](#markdown)
|
||||
- [Mermaid](#mermaid)
|
||||
- [Mechanik](#mechanik)
|
||||
- [Server](#server)
|
||||
- [Plesk](#plesk)
|
||||
- [Webserver](#webserver)
|
||||
- [Windows](#windows)
|
||||
- [Programmierung](#programmierung)
|
||||
- [Rust](#rust)
|
||||
- [ts - js - node](#ts---js---node)
|
||||
- [Projektinhalt](#projektinhalt)
|
||||
- [Neue Dokumente](#neue-dokumente)
|
||||
|
||||
---
|
||||
|
||||
## Informationen
|
||||
|
||||
Unter `./tools/` befinden sich Programme/ Skripte (aktuell in Typescript und Python) die Markdown-Dateien suchen und daraus ein Verzeichnis erstellen.
|
||||
|
||||
---
|
||||
|
||||
## Themen
|
||||
|
||||
---
|
||||
|
||||
### AsciiDoc
|
||||
|
||||
- [Asciidoctor PDF: Kapitel bleibt „Chapter“ – Fehleranalyse & Workaround](dokus/asciidoc/asciidoctor-theme-bug-workaround.md)
|
||||
|
||||
---
|
||||
|
||||
### Editoren/ IDE´s
|
||||
|
||||
#### Helix
|
||||
|
||||
- [Helix Editor – Ein umfassender Einstieg für Anfänger (Deutsch)](dokus/helix__editor_einfuehrung_de.md)
|
||||
|
||||
---
|
||||
|
||||
### Git
|
||||
|
||||
- [Artikel: git](dokus/git/git.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-Submodule: Der umfassende Praxisleitfaden](dokus/git/git-submodule-leitfaden.md)
|
||||
|
||||
### Markdown
|
||||
|
||||
#### Mermaid
|
||||
|
||||
- [mermaidPockedGuide](https://local.ionivation.com/realAscot/mermaidPockedGuide) **EXTERN** 🚀
|
||||
|
||||
### Mechanik
|
||||
|
||||
- [Gewindetabellen](dokus/mechanik/gewindetabellen.md)
|
||||
|
||||
---
|
||||
|
||||
### Server
|
||||
|
||||
#### Plesk
|
||||
|
||||
- [Plesk ausgesperrt bei Rechnerwechsel](dokus/plesk/plesk-benutzer-schon-vorhanden.md)
|
||||
|
||||
#### Webserver
|
||||
|
||||
- [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
|
||||
|
||||
- [Einführung in die `desktop.ini`-Datei: Verwendung und Anpassung von Ordnern in Windows](dokus/windows/desktop_ini.md)
|
||||
|
||||
---
|
||||
|
||||
### Programmierung
|
||||
|
||||
#### 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)
|
||||
|
||||
---
|
||||
|
||||
#### ts - js - node
|
||||
|
||||
- [Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration](dokus/js-ts/js-ts-dialekte.md)
|
||||
|
||||
---
|
||||
|
||||
## Projektinhalt
|
||||
|
||||
*Erstellt mit [treescanner](https://github.com/realAscot/treeScanner)*
|
||||
|
||||
```plaintext
|
||||
📁 ./
|
||||
├── 📁 dokus
|
||||
│ ├── 📁 apache-plesk
|
||||
│ │ └── 📄 lets-encrypt-plesk.md
|
||||
│ ├── 📁 asciidoc
|
||||
│ │ └── 📄 asciidoctor-theme-bug-workaround.md
|
||||
│ ├── 📁 git
|
||||
│ │ ├── 📄 git-remote-branch.md
|
||||
│ │ ├── 📄 git-ssh-remote.md
|
||||
│ │ ├── 📄 git-submodule-leitfaden.md
|
||||
│ │ └── 📄 git.md
|
||||
│ ├── 📁 js-ts
|
||||
│ │ └── 📄 js-ts-dialekte.md
|
||||
│ ├── 📁 mechanik
|
||||
│ │ └── 📄 gewindetabellen.md
|
||||
│ ├── 📁 plesk
|
||||
│ │ └── 📄 plesk-benutzer-schon-vorhanden.md
|
||||
│ ├── 📁 rust
|
||||
│ │ ├── 📄 rust-offline-installation.md
|
||||
│ │ └── 📄 rust-toolchain-msvc.md
|
||||
│ ├── 📁 windows
|
||||
│ │ └── 📄 desktop_ini.md
|
||||
│ └── 📄 helix__editor_einfuehrung_de.md
|
||||
├── 📁 media
|
||||
│ └── 📄 realAscotLogo_128x128.png
|
||||
├── 📁 tools
|
||||
│ ├── 📁 collector
|
||||
│ │ ├── 📄 config.jsonc
|
||||
│ │ ├── 📄 link_collector.js
|
||||
│ │ ├── 📄 link_collector.py
|
||||
│ │ └── 📄 processed.log
|
||||
│ ├── 📁 dist
|
||||
│ │ ├── 📁 collector
|
||||
│ │ ├── 📄 fscopy.js
|
||||
│ │ └── 📄 fsdel.js
|
||||
│ └── 📁 src
|
||||
│ ├── 📁 collector
|
||||
│ │ ├── 📄 config.jsonc.template
|
||||
│ │ └── 📄 link_collector.ts
|
||||
│ ├── 📄 fscopy.ts
|
||||
│ └── 📄 fsdel.ts
|
||||
├── 📄 .gitignore
|
||||
├── 📄 CHANGELOG.md
|
||||
├── 📄 LICENSE
|
||||
├── 📄 package-lock.json
|
||||
├── 📄 package.json
|
||||
├── 📄 README.md
|
||||
├── 📄 scan.cmd
|
||||
├── 📄 tsconfig.json
|
||||
└── 📄 VERSION
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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!
|
||||
|
||||
**NEUE EINTRÄGE AUS 'link_collector'->**
|
||||
|
||||
---
|
||||
|
@ -1,82 +1,82 @@
|
||||
# Asciidoctor PDF: Kapitel bleibt „Chapter“ – Fehleranalyse & Workaround
|
||||
|
||||
## 🧩 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**:
|
||||
|
||||
```text
|
||||
Chapter 1. Einführung
|
||||
```
|
||||
|
||||
…statt:
|
||||
|
||||
```text
|
||||
Kapitel 1. Einführung
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Erwartete Konfiguration
|
||||
|
||||
Folgendes wurde korrekt gesetzt:
|
||||
|
||||
- `chapter.title: "Kapitel {counter:chapter-number}. "` im Theme
|
||||
- `locale: lang` im Theme
|
||||
- Fonts korrekt eingebunden
|
||||
- `:lang: de` entfernt aus `.adoc` (zur Sicherheit)
|
||||
- Keine `de.yml` verwendet
|
||||
- Keine Snap-Version oder Paketkonflikte
|
||||
- Theme definitiv geladen (`font_size`, `base`, etc. wirksam)
|
||||
|
||||
---
|
||||
|
||||
## ❌ Ergebnis
|
||||
|
||||
Trotz aller Korrektheit:
|
||||
|
||||
- Ausgabe bleibt auf Englisch
|
||||
- Lokalisierung über Theme wird ignoriert
|
||||
- Das Verhalten ist **reproduzierbar auf mehreren Rechnern und Installationen**
|
||||
|
||||
---
|
||||
|
||||
## 🧨 Vermutete Ursache
|
||||
|
||||
Ein Bug oder ein Regressionseffekt in `asciidoctor-pdf` ab Version `2.3.0`, bei dem:
|
||||
|
||||
- entweder `chapter.title` aus Theme nicht mehr greift
|
||||
- oder durch eine andere Sprachverarbeitung überschrieben wird
|
||||
|
||||
---
|
||||
|
||||
## ✅ Workaround
|
||||
|
||||
Statt auf automatische Kapitelüberschriften zu setzen, diese manuell überschreiben:
|
||||
|
||||
### Im `.adoc`:
|
||||
|
||||
```asciidoc
|
||||
:sectnums!:
|
||||
|
||||
[discrete]
|
||||
== Kapitel 1. Einführung
|
||||
```
|
||||
|
||||
→ So wird die Kapitelzeile manuell gesetzt und `sectnums` deaktiviert.
|
||||
|
||||
---
|
||||
|
||||
## 📌 Empfehlung
|
||||
|
||||
- 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
|
||||
- Bis Bug behoben ist: Kapitel manuell beschriften oder alternative Engine verwenden
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Betroffene Versionen
|
||||
|
||||
- `asciidoctor-pdf 2.3.19`
|
||||
- `asciidoctor 2.0.23`
|
||||
- `ruby 3.1.x`
|
||||
- UTF-8 / Linux / WSL – identisches Verhalten
|
||||
# Asciidoctor PDF: Kapitel bleibt „Chapter“ – Fehleranalyse & Workaround
|
||||
|
||||
## 🧩 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**:
|
||||
|
||||
```text
|
||||
Chapter 1. Einführung
|
||||
```
|
||||
|
||||
…statt:
|
||||
|
||||
```text
|
||||
Kapitel 1. Einführung
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Erwartete Konfiguration
|
||||
|
||||
Folgendes wurde korrekt gesetzt:
|
||||
|
||||
- `chapter.title: "Kapitel {counter:chapter-number}. "` im Theme
|
||||
- `locale: lang` im Theme
|
||||
- Fonts korrekt eingebunden
|
||||
- `:lang: de` entfernt aus `.adoc` (zur Sicherheit)
|
||||
- Keine `de.yml` verwendet
|
||||
- Keine Snap-Version oder Paketkonflikte
|
||||
- Theme definitiv geladen (`font_size`, `base`, etc. wirksam)
|
||||
|
||||
---
|
||||
|
||||
## ❌ Ergebnis
|
||||
|
||||
Trotz aller Korrektheit:
|
||||
|
||||
- Ausgabe bleibt auf Englisch
|
||||
- Lokalisierung über Theme wird ignoriert
|
||||
- Das Verhalten ist **reproduzierbar auf mehreren Rechnern und Installationen**
|
||||
|
||||
---
|
||||
|
||||
## 🧨 Vermutete Ursache
|
||||
|
||||
Ein Bug oder ein Regressionseffekt in `asciidoctor-pdf` ab Version `2.3.0`, bei dem:
|
||||
|
||||
- entweder `chapter.title` aus Theme nicht mehr greift
|
||||
- oder durch eine andere Sprachverarbeitung überschrieben wird
|
||||
|
||||
---
|
||||
|
||||
## ✅ Workaround
|
||||
|
||||
Statt auf automatische Kapitelüberschriften zu setzen, diese manuell überschreiben:
|
||||
|
||||
### Im `.adoc`:
|
||||
|
||||
```asciidoc
|
||||
:sectnums!:
|
||||
|
||||
[discrete]
|
||||
== Kapitel 1. Einführung
|
||||
```
|
||||
|
||||
→ So wird die Kapitelzeile manuell gesetzt und `sectnums` deaktiviert.
|
||||
|
||||
---
|
||||
|
||||
## 📌 Empfehlung
|
||||
|
||||
- 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
|
||||
- Bis Bug behoben ist: Kapitel manuell beschriften oder alternative Engine verwenden
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Betroffene Versionen
|
||||
|
||||
- `asciidoctor-pdf 2.3.19`
|
||||
- `asciidoctor 2.0.23`
|
||||
- `ruby 3.1.x`
|
||||
- UTF-8 / Linux / WSL – identisches Verhalten
|
||||
|
@ -1,162 +1,162 @@
|
||||
# Git – Remote-Branches: Häufige Aufgaben und Lösungen
|
||||
|
||||
**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.
|
||||
|
||||
---
|
||||
|
||||
## 📌 Inhalt
|
||||
|
||||
- [Git – Remote-Branches: Häufige Aufgaben und Lösungen](#git--remote-branches-häufige-aufgaben-und-lösungen)
|
||||
- [📌 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)
|
||||
- [❓ 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)
|
||||
- [❓ 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)
|
||||
- [❓ 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)
|
||||
- [🧠 Zusammenfassung](#-zusammenfassung)
|
||||
|
||||
---
|
||||
|
||||
## ❓ 1. Wie hole ich einen Remote-Branch, den ich lokal noch nicht habe?
|
||||
|
||||
```bash
|
||||
git fetch
|
||||
git checkout -b <lokaler-name> origin/<remote-branch>
|
||||
```
|
||||
|
||||
Alternativ automatisch als Tracking-Branch:
|
||||
|
||||
```bash
|
||||
git checkout --track origin/<remote-branch>
|
||||
```
|
||||
|
||||
Beispiel:
|
||||
|
||||
```bash
|
||||
git checkout --track origin/feature/chat-system
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❓ 2. Warum sehe ich den Remote-Branch nicht in `git branch -r`?
|
||||
|
||||
`git branch -r` zeigt nur die lokal bekannten Remote-Refs.
|
||||
Du musst vorher `git fetch` ausführen:
|
||||
|
||||
```bash
|
||||
git fetch
|
||||
git branch -r
|
||||
```
|
||||
|
||||
Optional: erzwungen alles holen:
|
||||
|
||||
```bash
|
||||
git fetch origin '+refs/heads/*:refs/remotes/origin/*'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❓ 3. Holt `git clone` automatisch alle Branches?
|
||||
|
||||
**Nicht ganz.** `git clone`:
|
||||
|
||||
- ✅ holt alle Branches als Referenzen
|
||||
- ❌ checkt nur den Standard-Branch (z. B. `main`) lokal aus
|
||||
|
||||
**Weitere Branches** müssen manuell ausgecheckt werden:
|
||||
|
||||
```bash
|
||||
git checkout --track origin/<branch-name>
|
||||
```
|
||||
|
||||
Optional zur Sicherheit vorher:
|
||||
|
||||
```bash
|
||||
git fetch
|
||||
git branch -r
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❓ 4. Wie klone ich gezielt nur einen bestimmten Branch?
|
||||
|
||||
Nur den gewünschten Branch klonen (kein anderer wird geholt):
|
||||
|
||||
```bash
|
||||
git clone --branch <branch-name> --single-branch <repo-url>
|
||||
```
|
||||
|
||||
Mit reduziertem Verlauf (nur letzte Commits):
|
||||
|
||||
```bash
|
||||
git clone --branch <branch-name> --single-branch --depth 1 <repo-url>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❓ 5. Wann ist `--single-branch` sinnvoll?
|
||||
|
||||
Diese Variante ist ideal, wenn:
|
||||
|
||||
- du **nur an einem Branch arbeiten** willst
|
||||
- du **Platz oder Zeit sparen** möchtest
|
||||
- du das Repo **später einfach löschen** willst
|
||||
- du z. B. in **CI/CD**, **Docker**, **VMs** oder **temporär lokal** arbeitest
|
||||
|
||||
Sie vermeidet unnötige Daten und beschleunigt den Clone-Prozess.
|
||||
|
||||
---
|
||||
|
||||
## ❓ 6. Wie sehe ich alle Remote-Branches **vor** dem Clonen?
|
||||
|
||||
Du kannst dir **alle Branches am Remote-Repo anzeigen lassen**, ohne zu klonen:
|
||||
|
||||
```bash
|
||||
git ls-remote --heads <repo-url>
|
||||
```
|
||||
|
||||
Beispiel:
|
||||
|
||||
```bash
|
||||
git ls-remote --heads ssh://git@local.ionivation.com:2222/codewalker/codewalker.net.git
|
||||
```
|
||||
|
||||
Ergebnis:
|
||||
|
||||
```text
|
||||
f3a91d... refs/heads/main
|
||||
c4bd79... refs/heads/feature/chat-system
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Optionaler Alias-Tipp
|
||||
|
||||
Wenn du häufig neue Branches holen willst:
|
||||
|
||||
```bash
|
||||
git config --global alias.fr 'fetch && branch -r'
|
||||
```
|
||||
|
||||
Verwendung:
|
||||
|
||||
```bash
|
||||
git fr
|
||||
```
|
||||
|
||||
= `git fetch` + Anzeige aller Remote-Branches
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Zusammenfassung
|
||||
|
||||
| Ziel | Befehl |
|
||||
|-------------------------------------|------------------------------------------------------|
|
||||
| Remote-Branch holen + auschecken | `git fetch` + `git checkout --track origin/<name>` |
|
||||
| Nur einen Branch klonen | `git clone --branch <name> --single-branch <url>` |
|
||||
| Branchliste ohne Clone anzeigen | `git ls-remote --heads <repo-url>` |
|
||||
| Lokale Sichtbarkeit Remote-Branches | `git fetch` + `git branch -r` |
|
||||
# Git – Remote-Branches: Häufige Aufgaben und Lösungen
|
||||
|
||||
**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.
|
||||
|
||||
---
|
||||
|
||||
## 📌 Inhalt
|
||||
|
||||
- [Git – Remote-Branches: Häufige Aufgaben und Lösungen](#git--remote-branches-häufige-aufgaben-und-lösungen)
|
||||
- [📌 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)
|
||||
- [❓ 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)
|
||||
- [❓ 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)
|
||||
- [❓ 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)
|
||||
- [🧠 Zusammenfassung](#-zusammenfassung)
|
||||
|
||||
---
|
||||
|
||||
## ❓ 1. Wie hole ich einen Remote-Branch, den ich lokal noch nicht habe?
|
||||
|
||||
```bash
|
||||
git fetch
|
||||
git checkout -b <lokaler-name> origin/<remote-branch>
|
||||
```
|
||||
|
||||
Alternativ automatisch als Tracking-Branch:
|
||||
|
||||
```bash
|
||||
git checkout --track origin/<remote-branch>
|
||||
```
|
||||
|
||||
Beispiel:
|
||||
|
||||
```bash
|
||||
git checkout --track origin/feature/chat-system
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❓ 2. Warum sehe ich den Remote-Branch nicht in `git branch -r`?
|
||||
|
||||
`git branch -r` zeigt nur die lokal bekannten Remote-Refs.
|
||||
Du musst vorher `git fetch` ausführen:
|
||||
|
||||
```bash
|
||||
git fetch
|
||||
git branch -r
|
||||
```
|
||||
|
||||
Optional: erzwungen alles holen:
|
||||
|
||||
```bash
|
||||
git fetch origin '+refs/heads/*:refs/remotes/origin/*'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❓ 3. Holt `git clone` automatisch alle Branches?
|
||||
|
||||
**Nicht ganz.** `git clone`:
|
||||
|
||||
- ✅ holt alle Branches als Referenzen
|
||||
- ❌ checkt nur den Standard-Branch (z. B. `main`) lokal aus
|
||||
|
||||
**Weitere Branches** müssen manuell ausgecheckt werden:
|
||||
|
||||
```bash
|
||||
git checkout --track origin/<branch-name>
|
||||
```
|
||||
|
||||
Optional zur Sicherheit vorher:
|
||||
|
||||
```bash
|
||||
git fetch
|
||||
git branch -r
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❓ 4. Wie klone ich gezielt nur einen bestimmten Branch?
|
||||
|
||||
Nur den gewünschten Branch klonen (kein anderer wird geholt):
|
||||
|
||||
```bash
|
||||
git clone --branch <branch-name> --single-branch <repo-url>
|
||||
```
|
||||
|
||||
Mit reduziertem Verlauf (nur letzte Commits):
|
||||
|
||||
```bash
|
||||
git clone --branch <branch-name> --single-branch --depth 1 <repo-url>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❓ 5. Wann ist `--single-branch` sinnvoll?
|
||||
|
||||
Diese Variante ist ideal, wenn:
|
||||
|
||||
- du **nur an einem Branch arbeiten** willst
|
||||
- du **Platz oder Zeit sparen** möchtest
|
||||
- du das Repo **später einfach löschen** willst
|
||||
- du z. B. in **CI/CD**, **Docker**, **VMs** oder **temporär lokal** arbeitest
|
||||
|
||||
Sie vermeidet unnötige Daten und beschleunigt den Clone-Prozess.
|
||||
|
||||
---
|
||||
|
||||
## ❓ 6. Wie sehe ich alle Remote-Branches **vor** dem Clonen?
|
||||
|
||||
Du kannst dir **alle Branches am Remote-Repo anzeigen lassen**, ohne zu klonen:
|
||||
|
||||
```bash
|
||||
git ls-remote --heads <repo-url>
|
||||
```
|
||||
|
||||
Beispiel:
|
||||
|
||||
```bash
|
||||
git ls-remote --heads ssh://git@local.ionivation.com:2222/codewalker/codewalker.net.git
|
||||
```
|
||||
|
||||
Ergebnis:
|
||||
|
||||
```text
|
||||
f3a91d... refs/heads/main
|
||||
c4bd79... refs/heads/feature/chat-system
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Optionaler Alias-Tipp
|
||||
|
||||
Wenn du häufig neue Branches holen willst:
|
||||
|
||||
```bash
|
||||
git config --global alias.fr 'fetch && branch -r'
|
||||
```
|
||||
|
||||
Verwendung:
|
||||
|
||||
```bash
|
||||
git fr
|
||||
```
|
||||
|
||||
= `git fetch` + Anzeige aller Remote-Branches
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Zusammenfassung
|
||||
|
||||
| Ziel | Befehl |
|
||||
|-------------------------------------|------------------------------------------------------|
|
||||
| Remote-Branch holen + auschecken | `git fetch` + `git checkout --track origin/<name>` |
|
||||
| Nur einen Branch klonen | `git clone --branch <name> --single-branch <url>` |
|
||||
| Branchliste ohne Clone anzeigen | `git ls-remote --heads <repo-url>` |
|
||||
| Lokale Sichtbarkeit Remote-Branches | `git fetch` + `git branch -r` |
|
||||
|
@ -1,194 +1,194 @@
|
||||
# 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`.
|
||||
|
||||
- [SSH-Zugriff auf Git-Repository in WSL einrichten](#ssh-zugriff-auf-git-repository-in-wsl-einrichten)
|
||||
- [🔧 Voraussetzungen](#-voraussetzungen)
|
||||
- [🧱 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 3: SSH-Konfiguration (optional, empfohlen)](#️-schritt-3-ssh-konfiguration-optional-empfohlen)
|
||||
- [🧪 Schritt 4: Verbindung testen](#-schritt-4-verbindung-testen)
|
||||
- [🐙 Schritt 5: Git-Remote setzen oder klonen](#-schritt-5-git-remote-setzen-oder-klonen)
|
||||
- [✅ Bestehendes Repo umstellen](#-bestehendes-repo-umstellen)
|
||||
- [✅ Neues Repo klonen](#-neues-repo-klonen)
|
||||
- [🛡️ Hinweis: Keine Shell-Zugänge über Git-SSH](#️-hinweis-keine-shell-zugänge-über-git-ssh)
|
||||
- [✅ Fertig](#-fertig)
|
||||
- [🔁 Optional: Globale Git-Konfiguration absichern](#-optional-globale-git-konfiguration-absichern)
|
||||
- [🔑 SSH-Key unter WSL erzeugen](#-ssh-key-unter-wsl-erzeugen)
|
||||
- [🛠️ Voraussetzungen installieren](#️-voraussetzungen-installieren)
|
||||
- [🔐 SSH-Key erzeugen](#-ssh-key-erzeugen)
|
||||
- [⌨️ Bei der Abfrage:](#️-bei-der-abfrage)
|
||||
- [🔍 Public Key anzeigen](#-public-key-anzeigen)
|
||||
- [✅ Optional: SSH-Agent starten \& Schlüssel hinzufügen](#-optional-ssh-agent-starten--schlüssel-hinzufügen)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Voraussetzungen
|
||||
|
||||
- WSL ist eingerichtet (z. B. Ubuntu)
|
||||
- Ein Git-Server ist erreichbar (z. B. `git@dns.lan:2222`)
|
||||
- Du hast bereits Zugriff über Windows (z. B. via PowerShell)
|
||||
- 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.
|
||||
|
||||
---
|
||||
|
||||
## 🧱 Schritt 1: SSH-Verzeichnis in WSL anlegen
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.ssh
|
||||
chmod 700 ~/.ssh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗝️ 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:
|
||||
|
||||
```bash
|
||||
cp /mnt/c/Users/NAME/.ssh/id_ed25519 ~/.ssh/
|
||||
cp /mnt/c/Users/NAME/.ssh/id_ed25519.pub ~/.ssh/
|
||||
chmod 600 ~/.ssh/id_ed25519
|
||||
chmod 644 ~/.ssh/id_ed25519.pub
|
||||
```
|
||||
|
||||
🔁 Ersetze `NAME` mit deinem Windows-Benutzernamen.
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Schritt 3: SSH-Konfiguration (optional, empfohlen)
|
||||
|
||||
Erstelle (oder bearbeite) die Datei `~/.ssh/config`:
|
||||
|
||||
```bash
|
||||
nano ~/.ssh/config
|
||||
```
|
||||
|
||||
Füge ein:
|
||||
|
||||
```ssh
|
||||
Host gitea
|
||||
HostName dns.lan
|
||||
Port 2222
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
```
|
||||
|
||||
→ Damit kannst du den Hostname `gitea` als Alias verwenden.
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Schritt 4: Verbindung testen
|
||||
|
||||
```bash
|
||||
ssh -T gitea
|
||||
```
|
||||
|
||||
Erwartete Ausgabe:
|
||||
|
||||
```text
|
||||
Hi there, realAscot! You've successfully authenticated...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐙 Schritt 5: Git-Remote setzen oder klonen
|
||||
|
||||
### ✅ Bestehendes Repo umstellen
|
||||
|
||||
```bash
|
||||
git remote set-url origin gitea:realAscot/mein-projekt.git
|
||||
```
|
||||
|
||||
### ✅ Neues Repo klonen
|
||||
|
||||
```bash
|
||||
git clone gitea:realAscot/mein-projekt.git
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Hinweis: Keine Shell-Zugänge über Git-SSH
|
||||
|
||||
Wenn du folgende Meldung siehst:
|
||||
|
||||
```text
|
||||
You've successfully authenticated, but Gitea does not provide shell access.
|
||||
```
|
||||
|
||||
→ Das ist normal und **kein Fehler** – Push/Pull funktioniert trotzdem.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Fertig
|
||||
|
||||
Du kannst jetzt in WSL wie gewohnt per SSH arbeiten:
|
||||
|
||||
```bash
|
||||
git pull
|
||||
git push
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔁 Optional: Globale Git-Konfiguration absichern
|
||||
|
||||
```bash
|
||||
git config --global core.autocrlf input
|
||||
git config --global core.eol lf
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
## 🔑 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.
|
||||
|
||||
### 🛠️ Voraussetzungen installieren
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install -y openssh-client
|
||||
```
|
||||
|
||||
### 🔐 SSH-Key erzeugen
|
||||
|
||||
```bash
|
||||
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.
|
||||
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.
|
||||
Besser direkt angeben.
|
||||
|
||||
- **Erklärung:**
|
||||
|
||||
- `-t ed25519`: moderner, sicherer Algorithmus
|
||||
- `-C`: Kommentar (z. B. Mailadresse oder Systembeschreibung)
|
||||
|
||||
#### ⌨️ Bei der Abfrage:
|
||||
|
||||
- **Dateipfad**: einfach Enter drücken für Standard (`~/.ssh/id_ed25519_gitea`)
|
||||
- **Passphrase**: optional, aber empfohlen (für zusätzliche Sicherheit)
|
||||
|
||||
### 🔍 Public Key anzeigen
|
||||
|
||||
```bash
|
||||
cat ~/.ssh/id_ed25519_gitea.pub
|
||||
```
|
||||
|
||||
→ Diesen Schlüssel dann in **Gitea unter „SSH-Schlüssel“** einfügen.
|
||||
|
||||
### ✅ Optional: SSH-Agent starten & Schlüssel hinzufügen
|
||||
|
||||
```bash
|
||||
eval "$(ssh-agent -s)"
|
||||
ssh-add ~/.ssh/id_ed25519_gitea
|
||||
```
|
||||
|
||||
---
|
||||
# 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`.
|
||||
|
||||
- [SSH-Zugriff auf Git-Repository in WSL einrichten](#ssh-zugriff-auf-git-repository-in-wsl-einrichten)
|
||||
- [🔧 Voraussetzungen](#-voraussetzungen)
|
||||
- [🧱 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 3: SSH-Konfiguration (optional, empfohlen)](#️-schritt-3-ssh-konfiguration-optional-empfohlen)
|
||||
- [🧪 Schritt 4: Verbindung testen](#-schritt-4-verbindung-testen)
|
||||
- [🐙 Schritt 5: Git-Remote setzen oder klonen](#-schritt-5-git-remote-setzen-oder-klonen)
|
||||
- [✅ Bestehendes Repo umstellen](#-bestehendes-repo-umstellen)
|
||||
- [✅ Neues Repo klonen](#-neues-repo-klonen)
|
||||
- [🛡️ Hinweis: Keine Shell-Zugänge über Git-SSH](#️-hinweis-keine-shell-zugänge-über-git-ssh)
|
||||
- [✅ Fertig](#-fertig)
|
||||
- [🔁 Optional: Globale Git-Konfiguration absichern](#-optional-globale-git-konfiguration-absichern)
|
||||
- [🔑 SSH-Key unter WSL erzeugen](#-ssh-key-unter-wsl-erzeugen)
|
||||
- [🛠️ Voraussetzungen installieren](#️-voraussetzungen-installieren)
|
||||
- [🔐 SSH-Key erzeugen](#-ssh-key-erzeugen)
|
||||
- [⌨️ Bei der Abfrage:](#️-bei-der-abfrage)
|
||||
- [🔍 Public Key anzeigen](#-public-key-anzeigen)
|
||||
- [✅ Optional: SSH-Agent starten \& Schlüssel hinzufügen](#-optional-ssh-agent-starten--schlüssel-hinzufügen)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Voraussetzungen
|
||||
|
||||
- WSL ist eingerichtet (z. B. Ubuntu)
|
||||
- Ein Git-Server ist erreichbar (z. B. `git@dns.lan:2222`)
|
||||
- Du hast bereits Zugriff über Windows (z. B. via PowerShell)
|
||||
- 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.
|
||||
|
||||
---
|
||||
|
||||
## 🧱 Schritt 1: SSH-Verzeichnis in WSL anlegen
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.ssh
|
||||
chmod 700 ~/.ssh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗝️ 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:
|
||||
|
||||
```bash
|
||||
cp /mnt/c/Users/NAME/.ssh/id_ed25519 ~/.ssh/
|
||||
cp /mnt/c/Users/NAME/.ssh/id_ed25519.pub ~/.ssh/
|
||||
chmod 600 ~/.ssh/id_ed25519
|
||||
chmod 644 ~/.ssh/id_ed25519.pub
|
||||
```
|
||||
|
||||
🔁 Ersetze `NAME` mit deinem Windows-Benutzernamen.
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Schritt 3: SSH-Konfiguration (optional, empfohlen)
|
||||
|
||||
Erstelle (oder bearbeite) die Datei `~/.ssh/config`:
|
||||
|
||||
```bash
|
||||
nano ~/.ssh/config
|
||||
```
|
||||
|
||||
Füge ein:
|
||||
|
||||
```ssh
|
||||
Host gitea
|
||||
HostName dns.lan
|
||||
Port 2222
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
```
|
||||
|
||||
→ Damit kannst du den Hostname `gitea` als Alias verwenden.
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Schritt 4: Verbindung testen
|
||||
|
||||
```bash
|
||||
ssh -T gitea
|
||||
```
|
||||
|
||||
Erwartete Ausgabe:
|
||||
|
||||
```text
|
||||
Hi there, realAscot! You've successfully authenticated...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐙 Schritt 5: Git-Remote setzen oder klonen
|
||||
|
||||
### ✅ Bestehendes Repo umstellen
|
||||
|
||||
```bash
|
||||
git remote set-url origin gitea:realAscot/mein-projekt.git
|
||||
```
|
||||
|
||||
### ✅ Neues Repo klonen
|
||||
|
||||
```bash
|
||||
git clone gitea:realAscot/mein-projekt.git
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Hinweis: Keine Shell-Zugänge über Git-SSH
|
||||
|
||||
Wenn du folgende Meldung siehst:
|
||||
|
||||
```text
|
||||
You've successfully authenticated, but Gitea does not provide shell access.
|
||||
```
|
||||
|
||||
→ Das ist normal und **kein Fehler** – Push/Pull funktioniert trotzdem.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Fertig
|
||||
|
||||
Du kannst jetzt in WSL wie gewohnt per SSH arbeiten:
|
||||
|
||||
```bash
|
||||
git pull
|
||||
git push
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔁 Optional: Globale Git-Konfiguration absichern
|
||||
|
||||
```bash
|
||||
git config --global core.autocrlf input
|
||||
git config --global core.eol lf
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
## 🔑 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.
|
||||
|
||||
### 🛠️ Voraussetzungen installieren
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install -y openssh-client
|
||||
```
|
||||
|
||||
### 🔐 SSH-Key erzeugen
|
||||
|
||||
```bash
|
||||
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.
|
||||
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.
|
||||
Besser direkt angeben.
|
||||
|
||||
- **Erklärung:**
|
||||
|
||||
- `-t ed25519`: moderner, sicherer Algorithmus
|
||||
- `-C`: Kommentar (z. B. Mailadresse oder Systembeschreibung)
|
||||
|
||||
#### ⌨️ Bei der Abfrage:
|
||||
|
||||
- **Dateipfad**: einfach Enter drücken für Standard (`~/.ssh/id_ed25519_gitea`)
|
||||
- **Passphrase**: optional, aber empfohlen (für zusätzliche Sicherheit)
|
||||
|
||||
### 🔍 Public Key anzeigen
|
||||
|
||||
```bash
|
||||
cat ~/.ssh/id_ed25519_gitea.pub
|
||||
```
|
||||
|
||||
→ Diesen Schlüssel dann in **Gitea unter „SSH-Schlüssel“** einfügen.
|
||||
|
||||
### ✅ Optional: SSH-Agent starten & Schlüssel hinzufügen
|
||||
|
||||
```bash
|
||||
eval "$(ssh-agent -s)"
|
||||
ssh-add ~/.ssh/id_ed25519_gitea
|
||||
```
|
||||
|
||||
---
|
||||
|
@ -1,203 +1,203 @@
|
||||
# Git-Submodule: Der umfassende Praxisleitfaden
|
||||
|
||||
## Inhalt
|
||||
|
||||
- [Git-Submodule: Der umfassende Praxisleitfaden](#git-submodule-der-umfassende-praxisleitfaden)
|
||||
- [Inhalt](#inhalt)
|
||||
- [🔰 Was ist ein Git-Submodul?](#-was-ist-ein-git-submodul)
|
||||
- [🧱 Grundlagen](#-grundlagen)
|
||||
- [📌 `.gitmodules`](#-gitmodules)
|
||||
- [🧠 Merksatz](#-merksatz)
|
||||
- [🛠️ Submodul hinzufügen](#️-submodul-hinzufügen)
|
||||
- [🔄 Submodule aktualisieren](#-submodule-aktualisieren)
|
||||
- [📥 Klonen mit Submodulen](#-klonen-mit-submodulen)
|
||||
- [Methode 1: Inklusive Submodule](#methode-1-inklusive-submodule)
|
||||
- [Methode 2: Nachträglich initialisieren](#methode-2-nachträglich-initialisieren)
|
||||
- [🔃 Submodul-Synchronisation](#-submodul-synchronisation)
|
||||
- [📂 Weitere Remotes im Submodul](#-weitere-remotes-im-submodul)
|
||||
- [❗ Stolperfallen und Besonderheiten](#-stolperfallen-und-besonderheiten)
|
||||
- [🔄 Remote-URL wechseln](#-remote-url-wechseln)
|
||||
- [🚀 Push \& Pull Verhalten](#-push--pull-verhalten)
|
||||
- [🧼 Submodul löschen](#-submodul-löschen)
|
||||
- [🧰 Best Practices](#-best-practices)
|
||||
- [📎 Nützliche Kommandos](#-nützliche-kommandos)
|
||||
- [📑 Beispiel `.gitmodules` mit kommentierter Remote-Auswahl](#-beispiel-gitmodules-mit-kommentierter-remote-auswahl)
|
||||
- [🧭 Alternative: Subtree statt Submodul?](#-alternative-subtree-statt-submodul)
|
||||
- [📚 Fazit](#-fazit)
|
||||
- [🔗 Weiterführende Links](#-weiterführende-links)
|
||||
|
||||
---
|
||||
|
||||
## 🔰 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.
|
||||
|
||||
Beispielhafte Struktur:
|
||||
|
||||
```plaintext
|
||||
hauptprojekt/
|
||||
├── .gitmodules
|
||||
├── modul1/ ← eingebundenes Submodul
|
||||
└── modul2/
|
||||
```
|
||||
|
||||
## 🧱 Grundlagen
|
||||
|
||||
### 📌 `.gitmodules`
|
||||
|
||||
Diese Datei beschreibt Pfad und Remote-URL aller eingebundenen Submodule:
|
||||
|
||||
```ini
|
||||
[submodule "modul1"]
|
||||
path = modul1
|
||||
url = git@github.com:user/modul1.git
|
||||
```
|
||||
|
||||
### 🧠 Merksatz
|
||||
|
||||
> Submodule sind **Pointer auf einen bestimmten Commit** eines anderen Repositories.
|
||||
|
||||
## 🛠️ Submodul hinzufügen
|
||||
|
||||
```bash
|
||||
git submodule add <repo-url> <zielpfad>
|
||||
git commit -m "📦 Submodul hinzugefügt"
|
||||
```
|
||||
|
||||
Beispiel:
|
||||
|
||||
```bash
|
||||
git submodule add git@github.com:user/libmath.git extern/libmath
|
||||
```
|
||||
|
||||
Erzeugt:
|
||||
|
||||
- `.gitmodules`
|
||||
- Verzeichniseintrag im Git-Index
|
||||
- Initialer Checkout des Submoduls (HEAD auf Remote-Commit)
|
||||
|
||||
## 🔄 Submodule aktualisieren
|
||||
|
||||
```bash
|
||||
cd extern/libmath
|
||||
git pull origin main
|
||||
cd ../..
|
||||
git add extern/libmath
|
||||
git commit -m "🔄 Submodul libmath aktualisiert"
|
||||
```
|
||||
|
||||
> Nur das **Hauptrepo speichert den Commit-Zeiger**, nicht den Submodul-Inhalt selbst.
|
||||
|
||||
## 📥 Klonen mit Submodulen
|
||||
|
||||
### Methode 1: Inklusive Submodule
|
||||
|
||||
```bash
|
||||
git clone --recurse-submodules <url>
|
||||
```
|
||||
|
||||
### Methode 2: Nachträglich initialisieren
|
||||
|
||||
```bash
|
||||
git clone <url>
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
## 🔃 Submodul-Synchronisation
|
||||
|
||||
Wenn sich `.gitmodules` ändert (z. B. Remote-URL):
|
||||
|
||||
```bash
|
||||
git submodule sync
|
||||
```
|
||||
|
||||
## 📂 Weitere Remotes im Submodul
|
||||
|
||||
```bash
|
||||
cd modul1
|
||||
git remote add backup git@backup.server:repo.git
|
||||
```
|
||||
|
||||
> Diese Remotes sind **lokal**, nicht versioniert. `.gitmodules` kennt nur den Haupt-Remote.
|
||||
|
||||
## ❗ Stolperfallen und Besonderheiten
|
||||
|
||||
| Problem | Erklärung |
|
||||
|--------|-----------|
|
||||
| Submodul wird nicht mitgeclont | `--recurse-submodules` vergessen |
|
||||
| Ä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 |
|
||||
| Submodul zeigt „detached HEAD“ | normaler Zustand, wenn Submodul auf festen Commit gesetzt ist |
|
||||
|
||||
## 🔄 Remote-URL wechseln
|
||||
|
||||
```bash
|
||||
# In .gitmodules ändern oder per Befehl:
|
||||
git config -f .gitmodules submodule.modul1.url git@github.com:newuser/libmath.git
|
||||
git submodule sync
|
||||
```
|
||||
|
||||
## 🚀 Push & Pull Verhalten
|
||||
|
||||
| Aktion | Wirkung |
|
||||
|---------------------|---------|
|
||||
| `git push` im Hauptrepo | Pusht nur Zeiger auf Submodul-Commit |
|
||||
| `git push` im Submodul | Muss separat erfolgen |
|
||||
| `git pull` im Hauptrepo | Holt *nicht* automatisch neuen Submodul-Stand |
|
||||
|
||||
## 🧼 Submodul löschen
|
||||
|
||||
```bash
|
||||
# Schritt 1: Entfernen
|
||||
git submodule deinit -f pfad/zum/modul
|
||||
git rm -f pfad/zum/modul
|
||||
rm -rf .git/modules/pfad/zum/modul
|
||||
git commit -m "❌ Submodul entfernt"
|
||||
```
|
||||
|
||||
## 🧰 Best Practices
|
||||
|
||||
- **Nur stabile Submodul-Commits einchecken**, keine laufenden Branches.
|
||||
- **Submodule niemals blind aktualisieren** – Änderungen genau prüfen.
|
||||
- **Remote-Umschaltung dokumentieren oder automatisieren**, z. B. per Script.
|
||||
- **Submodule klein halten** – große, tief verschachtelte Strukturen vermeiden.
|
||||
- Für wiederverwendbare Bibliotheken oder Assets ideal (CAD, Snippets, Markdown, etc.).
|
||||
|
||||
## 📎 Nützliche Kommandos
|
||||
|
||||
```bash
|
||||
git submodule status # Überblick über alle Submodule
|
||||
git submodule update --init # Submodule initial holen
|
||||
git submodule update --remote # Auf neuesten Remote-Stand updaten
|
||||
git config -f .gitmodules ... # .gitmodules direkt bearbeiten
|
||||
```
|
||||
|
||||
## 📑 Beispiel `.gitmodules` mit kommentierter Remote-Auswahl
|
||||
|
||||
```ini
|
||||
[submodule "modul1"]
|
||||
path = modul1
|
||||
url = ssh://git@local.example.com:2222/myorg/modul1.git
|
||||
# url = git@github.com:myorg/modul1.git
|
||||
```
|
||||
|
||||
## 🧭 Alternative: Subtree statt Submodul?
|
||||
|
||||
Subtree ist einfacher zu verwalten, aber:
|
||||
|
||||
- kein fester Commit-Zeiger,
|
||||
- kein Remote-Wechsel ohne Umweg,
|
||||
- gemergte Historie im Hauptrepo.
|
||||
|
||||
**Submodul = getrennte Repos**
|
||||
**Subtree = eingemergter Inhalt**
|
||||
|
||||
## 📚 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.
|
||||
|
||||
## 🔗 Weiterführende Links
|
||||
|
||||
- [Git Book: Submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules)
|
||||
- [git-scm Doku: submodule](https://git-scm.com/docs/git-submodule)
|
||||
- [Vergleich Submodule vs. Subtree](https://www.atlassian.com/git/tutorials/git-submodule)
|
||||
# Git-Submodule: Der umfassende Praxisleitfaden
|
||||
|
||||
## Inhalt
|
||||
|
||||
- [Git-Submodule: Der umfassende Praxisleitfaden](#git-submodule-der-umfassende-praxisleitfaden)
|
||||
- [Inhalt](#inhalt)
|
||||
- [🔰 Was ist ein Git-Submodul?](#-was-ist-ein-git-submodul)
|
||||
- [🧱 Grundlagen](#-grundlagen)
|
||||
- [📌 `.gitmodules`](#-gitmodules)
|
||||
- [🧠 Merksatz](#-merksatz)
|
||||
- [🛠️ Submodul hinzufügen](#️-submodul-hinzufügen)
|
||||
- [🔄 Submodule aktualisieren](#-submodule-aktualisieren)
|
||||
- [📥 Klonen mit Submodulen](#-klonen-mit-submodulen)
|
||||
- [Methode 1: Inklusive Submodule](#methode-1-inklusive-submodule)
|
||||
- [Methode 2: Nachträglich initialisieren](#methode-2-nachträglich-initialisieren)
|
||||
- [🔃 Submodul-Synchronisation](#-submodul-synchronisation)
|
||||
- [📂 Weitere Remotes im Submodul](#-weitere-remotes-im-submodul)
|
||||
- [❗ Stolperfallen und Besonderheiten](#-stolperfallen-und-besonderheiten)
|
||||
- [🔄 Remote-URL wechseln](#-remote-url-wechseln)
|
||||
- [🚀 Push \& Pull Verhalten](#-push--pull-verhalten)
|
||||
- [🧼 Submodul löschen](#-submodul-löschen)
|
||||
- [🧰 Best Practices](#-best-practices)
|
||||
- [📎 Nützliche Kommandos](#-nützliche-kommandos)
|
||||
- [📑 Beispiel `.gitmodules` mit kommentierter Remote-Auswahl](#-beispiel-gitmodules-mit-kommentierter-remote-auswahl)
|
||||
- [🧭 Alternative: Subtree statt Submodul?](#-alternative-subtree-statt-submodul)
|
||||
- [📚 Fazit](#-fazit)
|
||||
- [🔗 Weiterführende Links](#-weiterführende-links)
|
||||
|
||||
---
|
||||
|
||||
## 🔰 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.
|
||||
|
||||
Beispielhafte Struktur:
|
||||
|
||||
```plaintext
|
||||
hauptprojekt/
|
||||
├── .gitmodules
|
||||
├── modul1/ ← eingebundenes Submodul
|
||||
└── modul2/
|
||||
```
|
||||
|
||||
## 🧱 Grundlagen
|
||||
|
||||
### 📌 `.gitmodules`
|
||||
|
||||
Diese Datei beschreibt Pfad und Remote-URL aller eingebundenen Submodule:
|
||||
|
||||
```ini
|
||||
[submodule "modul1"]
|
||||
path = modul1
|
||||
url = git@github.com:user/modul1.git
|
||||
```
|
||||
|
||||
### 🧠 Merksatz
|
||||
|
||||
> Submodule sind **Pointer auf einen bestimmten Commit** eines anderen Repositories.
|
||||
|
||||
## 🛠️ Submodul hinzufügen
|
||||
|
||||
```bash
|
||||
git submodule add <repo-url> <zielpfad>
|
||||
git commit -m "📦 Submodul hinzugefügt"
|
||||
```
|
||||
|
||||
Beispiel:
|
||||
|
||||
```bash
|
||||
git submodule add git@github.com:user/libmath.git extern/libmath
|
||||
```
|
||||
|
||||
Erzeugt:
|
||||
|
||||
- `.gitmodules`
|
||||
- Verzeichniseintrag im Git-Index
|
||||
- Initialer Checkout des Submoduls (HEAD auf Remote-Commit)
|
||||
|
||||
## 🔄 Submodule aktualisieren
|
||||
|
||||
```bash
|
||||
cd extern/libmath
|
||||
git pull origin main
|
||||
cd ../..
|
||||
git add extern/libmath
|
||||
git commit -m "🔄 Submodul libmath aktualisiert"
|
||||
```
|
||||
|
||||
> Nur das **Hauptrepo speichert den Commit-Zeiger**, nicht den Submodul-Inhalt selbst.
|
||||
|
||||
## 📥 Klonen mit Submodulen
|
||||
|
||||
### Methode 1: Inklusive Submodule
|
||||
|
||||
```bash
|
||||
git clone --recurse-submodules <url>
|
||||
```
|
||||
|
||||
### Methode 2: Nachträglich initialisieren
|
||||
|
||||
```bash
|
||||
git clone <url>
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
## 🔃 Submodul-Synchronisation
|
||||
|
||||
Wenn sich `.gitmodules` ändert (z. B. Remote-URL):
|
||||
|
||||
```bash
|
||||
git submodule sync
|
||||
```
|
||||
|
||||
## 📂 Weitere Remotes im Submodul
|
||||
|
||||
```bash
|
||||
cd modul1
|
||||
git remote add backup git@backup.server:repo.git
|
||||
```
|
||||
|
||||
> Diese Remotes sind **lokal**, nicht versioniert. `.gitmodules` kennt nur den Haupt-Remote.
|
||||
|
||||
## ❗ Stolperfallen und Besonderheiten
|
||||
|
||||
| Problem | Erklärung |
|
||||
|--------|-----------|
|
||||
| Submodul wird nicht mitgeclont | `--recurse-submodules` vergessen |
|
||||
| Ä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 |
|
||||
| Submodul zeigt „detached HEAD“ | normaler Zustand, wenn Submodul auf festen Commit gesetzt ist |
|
||||
|
||||
## 🔄 Remote-URL wechseln
|
||||
|
||||
```bash
|
||||
# In .gitmodules ändern oder per Befehl:
|
||||
git config -f .gitmodules submodule.modul1.url git@github.com:newuser/libmath.git
|
||||
git submodule sync
|
||||
```
|
||||
|
||||
## 🚀 Push & Pull Verhalten
|
||||
|
||||
| Aktion | Wirkung |
|
||||
|---------------------|---------|
|
||||
| `git push` im Hauptrepo | Pusht nur Zeiger auf Submodul-Commit |
|
||||
| `git push` im Submodul | Muss separat erfolgen |
|
||||
| `git pull` im Hauptrepo | Holt *nicht* automatisch neuen Submodul-Stand |
|
||||
|
||||
## 🧼 Submodul löschen
|
||||
|
||||
```bash
|
||||
# Schritt 1: Entfernen
|
||||
git submodule deinit -f pfad/zum/modul
|
||||
git rm -f pfad/zum/modul
|
||||
rm -rf .git/modules/pfad/zum/modul
|
||||
git commit -m "❌ Submodul entfernt"
|
||||
```
|
||||
|
||||
## 🧰 Best Practices
|
||||
|
||||
- **Nur stabile Submodul-Commits einchecken**, keine laufenden Branches.
|
||||
- **Submodule niemals blind aktualisieren** – Änderungen genau prüfen.
|
||||
- **Remote-Umschaltung dokumentieren oder automatisieren**, z. B. per Script.
|
||||
- **Submodule klein halten** – große, tief verschachtelte Strukturen vermeiden.
|
||||
- Für wiederverwendbare Bibliotheken oder Assets ideal (CAD, Snippets, Markdown, etc.).
|
||||
|
||||
## 📎 Nützliche Kommandos
|
||||
|
||||
```bash
|
||||
git submodule status # Überblick über alle Submodule
|
||||
git submodule update --init # Submodule initial holen
|
||||
git submodule update --remote # Auf neuesten Remote-Stand updaten
|
||||
git config -f .gitmodules ... # .gitmodules direkt bearbeiten
|
||||
```
|
||||
|
||||
## 📑 Beispiel `.gitmodules` mit kommentierter Remote-Auswahl
|
||||
|
||||
```ini
|
||||
[submodule "modul1"]
|
||||
path = modul1
|
||||
url = ssh://git@local.example.com:2222/myorg/modul1.git
|
||||
# url = git@github.com:myorg/modul1.git
|
||||
```
|
||||
|
||||
## 🧭 Alternative: Subtree statt Submodul?
|
||||
|
||||
Subtree ist einfacher zu verwalten, aber:
|
||||
|
||||
- kein fester Commit-Zeiger,
|
||||
- kein Remote-Wechsel ohne Umweg,
|
||||
- gemergte Historie im Hauptrepo.
|
||||
|
||||
**Submodul = getrennte Repos**
|
||||
**Subtree = eingemergter Inhalt**
|
||||
|
||||
## 📚 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.
|
||||
|
||||
## 🔗 Weiterführende Links
|
||||
|
||||
- [Git Book: Submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules)
|
||||
- [git-scm Doku: submodule](https://git-scm.com/docs/git-submodule)
|
||||
- [Vergleich Submodule vs. Subtree](https://www.atlassian.com/git/tutorials/git-submodule)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Artikel: git
|
||||
|
||||
- [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)
|
||||
# Artikel: git
|
||||
|
||||
- [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)
|
||||
|
@ -1,182 +1,182 @@
|
||||
# Helix Editor – Ein umfassender Einstieg für Anfänger (Deutsch)
|
||||
|
||||
## Inhalt
|
||||
|
||||
- [Helix Editor – Ein umfassender Einstieg für Anfänger (Deutsch)](#helix-editor--ein-umfassender-einstieg-für-anfänger-deutsch)
|
||||
- [Inhalt](#inhalt)
|
||||
- [✨ Was ist Helix?](#-was-ist-helix)
|
||||
- [🔧 Installation](#-installation)
|
||||
- [Linux (Fedora, Arch, Debian)](#linux-fedora-arch-debian)
|
||||
- [GitHub Release (empfohlen für aktuellste Version)](#github-release-empfohlen-für-aktuellste-version)
|
||||
- [📁 Erstes Projekt starten](#-erstes-projekt-starten)
|
||||
- [Beispiel: Rust-Projekt](#beispiel-rust-projekt)
|
||||
- [Beispiel: JavaScript-Projekt](#beispiel-javascript-projekt)
|
||||
- [⌨ Bedienkonzept von Helix](#-bedienkonzept-von-helix)
|
||||
- [Modale Steuerung (ähnlich wie Vim)](#modale-steuerung-ähnlich-wie-vim)
|
||||
- [Wechsel der Modi](#wechsel-der-modi)
|
||||
- [⚖️ Wichtige Tastenkombinationen](#️-wichtige-tastenkombinationen)
|
||||
- [🪨 Sprachserver (LSP)](#-sprachserver-lsp)
|
||||
- [Rust](#rust)
|
||||
- [JavaScript/TypeScript](#javascripttypescript)
|
||||
- [C / C++](#c--c)
|
||||
- [⚖️ LSP-Befehle in Helix](#️-lsp-befehle-in-helix)
|
||||
- [📂 Konfiguration](#-konfiguration)
|
||||
- [Beispiel-Inhalt](#beispiel-inhalt)
|
||||
- [🌍 Weitere Ressourcen](#-weitere-ressourcen)
|
||||
|
||||
## ✨ 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.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Installation
|
||||
|
||||
### Linux (Fedora, Arch, Debian)
|
||||
|
||||
```bash
|
||||
# Fedora
|
||||
sudo dnf install helix
|
||||
|
||||
# Arch (via pacman)
|
||||
sudo pacman -S helix
|
||||
|
||||
# Debian/Ubuntu (nur in neueren Versionen oder via GitHub)
|
||||
```
|
||||
|
||||
### GitHub Release (empfohlen für aktuellste Version)
|
||||
|
||||
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
|
||||
3. Entpacken:
|
||||
|
||||
```bash
|
||||
tar -xvf helix-*-x86_64-linux.tar.xz
|
||||
sudo cp helix-*/helix/hx /usr/local/bin/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 Erstes Projekt starten
|
||||
|
||||
### Beispiel: Rust-Projekt
|
||||
|
||||
```bash
|
||||
cargo new hallo_helix
|
||||
cd hallo_helix
|
||||
hx src/main.rs
|
||||
```
|
||||
|
||||
### Beispiel: JavaScript-Projekt
|
||||
|
||||
```bash
|
||||
mkdir node_hello && cd node_hello
|
||||
echo 'console.log("Hallo, Welt!");' > index.js
|
||||
hx index.js
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⌨ Bedienkonzept von Helix
|
||||
|
||||
### Modale Steuerung (ähnlich wie Vim)
|
||||
|
||||
- **Normalmodus**: Standardmodus zum Navigieren und Bearbeiten
|
||||
- **Einfügemodus (Insert)**: `i` drücken zum Schreiben
|
||||
- **Auswahlmodus (Select)**: `v` für Zeichenweise, `V` für Zeilenweise Auswahl
|
||||
|
||||
### Wechsel der Modi
|
||||
|
||||
| Modus | Taste | Funktion |
|
||||
| ----------- | ----- | ----------------------- |
|
||||
| Normal | `Esc` | Zur Steuerung & Befehle |
|
||||
| Insert | `i` | Einfügen / Tippen |
|
||||
| Select | `v` | Auswahl ab Cursor |
|
||||
| Line-Select | `V` | Ganze Zeile auswählen |
|
||||
|
||||
---
|
||||
|
||||
## ⚖️ Wichtige Tastenkombinationen
|
||||
|
||||
| Tastenkombi | Bedeutung |
|
||||
| ----------- | --------------------------------- |
|
||||
| `:w` | Datei speichern |
|
||||
| `:q` | Editor beenden |
|
||||
| `:wq` | Speichern und beenden |
|
||||
| `g g` | Zum Anfang der Datei |
|
||||
| `G` | Zum Ende der Datei |
|
||||
| `d d` | Aktuelle Zeile löschen |
|
||||
| `u` | Letzte Änderung rückgängig machen |
|
||||
| `space + /` | Fuzzy-Dateisuche starten |
|
||||
| `space + g` | Git-Diff anzeigen |
|
||||
|
||||
---
|
||||
|
||||
## 🪨 Sprachserver (LSP)
|
||||
|
||||
Helix erkennt automatisch den Dateityp und startet den passenden Sprachserver:
|
||||
|
||||
### Rust
|
||||
|
||||
```bash
|
||||
rustup component add rust-analyzer
|
||||
```
|
||||
|
||||
### JavaScript/TypeScript
|
||||
|
||||
```bash
|
||||
npm install -g typescript typescript-language-server
|
||||
```
|
||||
|
||||
### C / C++
|
||||
|
||||
```bash
|
||||
sudo dnf install clang clang-tools-extra
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚖️ LSP-Befehle in Helix
|
||||
|
||||
| Taste | Bedeutung |
|
||||
| ----- | ------------------------------- |
|
||||
| `g d` | Gehe zur Definition |
|
||||
| `g r` | Gehe zu Referenzen |
|
||||
| `K` | Hover-Info anzeigen (Typ, Doku) |
|
||||
| `=` | Formatieren |
|
||||
|
||||
---
|
||||
|
||||
## 📂 Konfiguration
|
||||
|
||||
Helix-Konfiguration liegt unter:
|
||||
|
||||
```bash
|
||||
~/.config/helix/config.toml
|
||||
```
|
||||
|
||||
Zum Öffnen:
|
||||
|
||||
```bash
|
||||
:config-open
|
||||
```
|
||||
|
||||
### Beispiel-Inhalt
|
||||
|
||||
```toml
|
||||
theme = "base16_default_dark"
|
||||
|
||||
[keys.normal]
|
||||
"C-s" = ":w"
|
||||
"C-q" = ":wq"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌍 Weitere Ressourcen
|
||||
|
||||
- Offizielle Seite: [https://helix-editor.com](https://helix-editor.com)
|
||||
- GitHub: [https://github.com/helix-editor/helix](https://github.com/helix-editor/helix)
|
||||
- Tastenkombis: [https://docs.helix-editor.com/](https://docs.helix-editor.com/)
|
||||
|
||||
---
|
||||
# Helix Editor – Ein umfassender Einstieg für Anfänger (Deutsch)
|
||||
|
||||
## Inhalt
|
||||
|
||||
- [Helix Editor – Ein umfassender Einstieg für Anfänger (Deutsch)](#helix-editor--ein-umfassender-einstieg-für-anfänger-deutsch)
|
||||
- [Inhalt](#inhalt)
|
||||
- [✨ Was ist Helix?](#-was-ist-helix)
|
||||
- [🔧 Installation](#-installation)
|
||||
- [Linux (Fedora, Arch, Debian)](#linux-fedora-arch-debian)
|
||||
- [GitHub Release (empfohlen für aktuellste Version)](#github-release-empfohlen-für-aktuellste-version)
|
||||
- [📁 Erstes Projekt starten](#-erstes-projekt-starten)
|
||||
- [Beispiel: Rust-Projekt](#beispiel-rust-projekt)
|
||||
- [Beispiel: JavaScript-Projekt](#beispiel-javascript-projekt)
|
||||
- [⌨ Bedienkonzept von Helix](#-bedienkonzept-von-helix)
|
||||
- [Modale Steuerung (ähnlich wie Vim)](#modale-steuerung-ähnlich-wie-vim)
|
||||
- [Wechsel der Modi](#wechsel-der-modi)
|
||||
- [⚖️ Wichtige Tastenkombinationen](#️-wichtige-tastenkombinationen)
|
||||
- [🪨 Sprachserver (LSP)](#-sprachserver-lsp)
|
||||
- [Rust](#rust)
|
||||
- [JavaScript/TypeScript](#javascripttypescript)
|
||||
- [C / C++](#c--c)
|
||||
- [⚖️ LSP-Befehle in Helix](#️-lsp-befehle-in-helix)
|
||||
- [📂 Konfiguration](#-konfiguration)
|
||||
- [Beispiel-Inhalt](#beispiel-inhalt)
|
||||
- [🌍 Weitere Ressourcen](#-weitere-ressourcen)
|
||||
|
||||
## ✨ 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.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Installation
|
||||
|
||||
### Linux (Fedora, Arch, Debian)
|
||||
|
||||
```bash
|
||||
# Fedora
|
||||
sudo dnf install helix
|
||||
|
||||
# Arch (via pacman)
|
||||
sudo pacman -S helix
|
||||
|
||||
# Debian/Ubuntu (nur in neueren Versionen oder via GitHub)
|
||||
```
|
||||
|
||||
### GitHub Release (empfohlen für aktuellste Version)
|
||||
|
||||
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
|
||||
3. Entpacken:
|
||||
|
||||
```bash
|
||||
tar -xvf helix-*-x86_64-linux.tar.xz
|
||||
sudo cp helix-*/helix/hx /usr/local/bin/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 Erstes Projekt starten
|
||||
|
||||
### Beispiel: Rust-Projekt
|
||||
|
||||
```bash
|
||||
cargo new hallo_helix
|
||||
cd hallo_helix
|
||||
hx src/main.rs
|
||||
```
|
||||
|
||||
### Beispiel: JavaScript-Projekt
|
||||
|
||||
```bash
|
||||
mkdir node_hello && cd node_hello
|
||||
echo 'console.log("Hallo, Welt!");' > index.js
|
||||
hx index.js
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⌨ Bedienkonzept von Helix
|
||||
|
||||
### Modale Steuerung (ähnlich wie Vim)
|
||||
|
||||
- **Normalmodus**: Standardmodus zum Navigieren und Bearbeiten
|
||||
- **Einfügemodus (Insert)**: `i` drücken zum Schreiben
|
||||
- **Auswahlmodus (Select)**: `v` für Zeichenweise, `V` für Zeilenweise Auswahl
|
||||
|
||||
### Wechsel der Modi
|
||||
|
||||
| Modus | Taste | Funktion |
|
||||
| ----------- | ----- | ----------------------- |
|
||||
| Normal | `Esc` | Zur Steuerung & Befehle |
|
||||
| Insert | `i` | Einfügen / Tippen |
|
||||
| Select | `v` | Auswahl ab Cursor |
|
||||
| Line-Select | `V` | Ganze Zeile auswählen |
|
||||
|
||||
---
|
||||
|
||||
## ⚖️ Wichtige Tastenkombinationen
|
||||
|
||||
| Tastenkombi | Bedeutung |
|
||||
| ----------- | --------------------------------- |
|
||||
| `:w` | Datei speichern |
|
||||
| `:q` | Editor beenden |
|
||||
| `:wq` | Speichern und beenden |
|
||||
| `g g` | Zum Anfang der Datei |
|
||||
| `G` | Zum Ende der Datei |
|
||||
| `d d` | Aktuelle Zeile löschen |
|
||||
| `u` | Letzte Änderung rückgängig machen |
|
||||
| `space + /` | Fuzzy-Dateisuche starten |
|
||||
| `space + g` | Git-Diff anzeigen |
|
||||
|
||||
---
|
||||
|
||||
## 🪨 Sprachserver (LSP)
|
||||
|
||||
Helix erkennt automatisch den Dateityp und startet den passenden Sprachserver:
|
||||
|
||||
### Rust
|
||||
|
||||
```bash
|
||||
rustup component add rust-analyzer
|
||||
```
|
||||
|
||||
### JavaScript/TypeScript
|
||||
|
||||
```bash
|
||||
npm install -g typescript typescript-language-server
|
||||
```
|
||||
|
||||
### C / C++
|
||||
|
||||
```bash
|
||||
sudo dnf install clang clang-tools-extra
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚖️ LSP-Befehle in Helix
|
||||
|
||||
| Taste | Bedeutung |
|
||||
| ----- | ------------------------------- |
|
||||
| `g d` | Gehe zur Definition |
|
||||
| `g r` | Gehe zu Referenzen |
|
||||
| `K` | Hover-Info anzeigen (Typ, Doku) |
|
||||
| `=` | Formatieren |
|
||||
|
||||
---
|
||||
|
||||
## 📂 Konfiguration
|
||||
|
||||
Helix-Konfiguration liegt unter:
|
||||
|
||||
```bash
|
||||
~/.config/helix/config.toml
|
||||
```
|
||||
|
||||
Zum Öffnen:
|
||||
|
||||
```bash
|
||||
:config-open
|
||||
```
|
||||
|
||||
### Beispiel-Inhalt
|
||||
|
||||
```toml
|
||||
theme = "base16_default_dark"
|
||||
|
||||
[keys.normal]
|
||||
"C-s" = ":w"
|
||||
"C-q" = ":wq"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌍 Weitere Ressourcen
|
||||
|
||||
- Offizielle Seite: [https://helix-editor.com](https://helix-editor.com)
|
||||
- GitHub: [https://github.com/helix-editor/helix](https://github.com/helix-editor/helix)
|
||||
- Tastenkombis: [https://docs.helix-editor.com/](https://docs.helix-editor.com/)
|
||||
|
||||
---
|
||||
|
@ -1,345 +1,345 @@
|
||||
# Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration
|
||||
|
||||
## ✨ 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.
|
||||
|
||||
## Inhalt
|
||||
|
||||
- [Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration](#einstieg-in-javascript-dialekte-und-typescript-konfiguration)
|
||||
- [✨ Ziel dieses Dokuments](#-ziel-dieses-dokuments)
|
||||
- [Inhalt](#inhalt)
|
||||
- [🔢 Begriffe erklärt](#-begriffe-erklärt)
|
||||
- [JavaScript-Dialekte (Modulsysteme)](#javascript-dialekte-modulsysteme)
|
||||
- [Was ist TypeScript?](#was-ist-typescript)
|
||||
- [🔍 Wann verwende ich was?](#-wann-verwende-ich-was)
|
||||
- [🔧 TypeScript richtig konfigurieren](#-typescript-richtig-konfigurieren)
|
||||
- [📦 Was ist ESM?](#-was-ist-esm)
|
||||
- [✅ Wann kann/sollte/muss man **ESM** verwenden?](#-wann-kannsolltemuss-man-esm-verwenden)
|
||||
- [🟢 **Du kannst ESM verwenden**, wenn](#-du-kannst-esm-verwenden-wenn)
|
||||
- [🟡 **Du solltest ESM verwenden**, wenn](#-du-solltest-esm-verwenden-wenn)
|
||||
- [🔴 **Du musst ESM verwenden**, wenn](#-du-musst-esm-verwenden-wenn)
|
||||
- [⚙️ TypeScript-Konfiguration für ESM](#️-typescript-konfiguration-für-esm)
|
||||
- [📌 Merkmale von ESM](#-merkmale-von-esm)
|
||||
- [⚠️ Besonderheiten und Stolperfallen](#️-besonderheiten-und-stolperfallen)
|
||||
- [✅ Fazit ESM](#-fazit-esm)
|
||||
- [🌐 CommonJS-Konfiguration CJS (Alternative)](#-commonjs-konfiguration-cjs-alternative)
|
||||
- [📦 Was ist CommonJS?](#-was-ist-commonjs)
|
||||
- [✅ Wann kann/sollte/muss man **CommonJS** verwenden?](#-wann-kannsolltemuss-man-commonjs-verwenden)
|
||||
- [🟢 **Du kannst CJS verwenden**, wenn](#-du-kannst-cjs-verwenden-wenn)
|
||||
- [🟡 **Du solltest CJS verwenden**, wenn](#-du-solltest-cjs-verwenden-wenn)
|
||||
- [🔴 **Du musst CJS verwenden**, wenn](#-du-musst-cjs-verwenden-wenn)
|
||||
- [⚙️ TypeScript-Konfiguration für CJS](#️-typescript-konfiguration-für-cjs)
|
||||
- [📌 Merkmale von CommonJS](#-merkmale-von-commonjs)
|
||||
- [✅ Fazit CommonJS](#-fazit-commonjs)
|
||||
- [📄 Fazit: Empfehlungen](#-fazit-empfehlungen)
|
||||
- [📁 Dateiendungen in Node.js](#-dateiendungen-in-nodejs)
|
||||
- [⚠️ Typische Fehler vermeiden](#️-typische-fehler-vermeiden)
|
||||
- [🚀 CLI-Build-Tipps (tsc)](#-cli-build-tipps-tsc)
|
||||
- [📍 Weiterführende Themen](#-weiterführende-themen)
|
||||
|
||||
---
|
||||
|
||||
## 🔢 Begriffe erklärt
|
||||
|
||||
### JavaScript-Dialekte (Modulsysteme)
|
||||
|
||||
| Name | Kürzel | Typ | Verwendung heute |
|
||||
| ------------------ | ------ | ----------- | ----------------------- |
|
||||
| CommonJS | CJS | `require()` | Ältere Node.js-Projekte |
|
||||
| ECMAScript Modules | ESM | `import` | Browser, moderne Tools |
|
||||
|
||||
- **CommonJS:** Nutzt `require()` und `module.exports`. Standard bis Node 12.
|
||||
- **ESM:** Nutzt `import`/`export`. Standard im Browser und in Node ab Version 14+.
|
||||
|
||||
### Was ist TypeScript?
|
||||
|
||||
TypeScript ist eine statisch typisierte Obermenge von JavaScript, die zu normalem JS kompiliert wird.
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Wann verwende ich was?
|
||||
|
||||
| Ziel | Modulformat | Empfehlung | Grund |
|
||||
| -------------------------- | ------------ | -------------- | ------------------------------------------ |
|
||||
| 📅 Moderne Webanwendung | ESM | Ja | Browser erwartet ESM |
|
||||
| 📄 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 |
|
||||
| 🔌 Electron Renderer | ESM | Ja (Pflicht) | Chromium-only, kein CJS |
|
||||
| 🔁 Vite/Webpack-Projekt | ESM | Ja | Toolchain basiert auf ESM |
|
||||
|
||||
---
|
||||
|
||||
## 🔧 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.
|
||||
|
||||
---
|
||||
|
||||
### 📦 Was ist ESM?
|
||||
|
||||
**ESM (ECMAScript Modules)** ist das moderne Modulsystem von JavaScript:
|
||||
|
||||
- verwendet `import`/`export`-Syntax
|
||||
- wird nativ von allen modernen Browsern und Node.js (ab v14+) unterstützt
|
||||
- ist Standard in allen modernen JS-Toolchains (Vite, Webpack, esbuild, etc.)
|
||||
|
||||
```js
|
||||
// ESM-Stil
|
||||
import fs from 'node:fs/promises';
|
||||
export function read(path) {
|
||||
return fs.readFile(path, 'utf-8');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### ✅ Wann kann/sollte/muss man **ESM** verwenden?
|
||||
|
||||
#### 🟢 **Du kannst ESM verwenden**, wenn
|
||||
|
||||
- du mit **modernen Node.js-Versionen (v16+)** arbeitest
|
||||
- du ein **Frontend-Tool** oder ein **Browser-kompatibles Projekt** baust
|
||||
- du Tree-Shaking oder Dynamic `import()` nutzen willst
|
||||
- du Typkonsistenz mit dem Browser willst (gleiche Syntax wie dort)
|
||||
|
||||
#### 🟡 **Du solltest ESM verwenden**, wenn
|
||||
|
||||
| Situation | Grund |
|
||||
| ------------------------------------------------------------------- | ---------------------------- |
|
||||
| 🌐 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 willst `import()` dynamisch verwenden | Nur in ESM verfügbar |
|
||||
| 📚 Du schreibst eine wiederverwendbare Bibliothek für neue Projekte | Zukunftssicherheit |
|
||||
| 🧩 Du verwendest Deno, Bun oder moderne Plattformen | ESM only |
|
||||
|
||||
#### 🔴 **Du musst ESM verwenden**, wenn
|
||||
|
||||
- du im **Browser** arbeitest (ohne Bundler) → dort ist `import` Pflicht
|
||||
- du in **Electron-Renderer-Prozessen** arbeitest
|
||||
- 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`)
|
||||
|
||||
---
|
||||
|
||||
### ⚙️ TypeScript-Konfiguration für ESM
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Und in der `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
```
|
||||
|
||||
**Wichtig:** Ohne `"type": "module"` behandelt Node deine `.js`-Dateien **nicht als ESM**, sondern als CommonJS.
|
||||
|
||||
---
|
||||
|
||||
### 📌 Merkmale von ESM
|
||||
|
||||
| Merkmal | ESM |
|
||||
| ------------------------- | -------------------------------------------- |
|
||||
| Import-Syntax | `import`, `export` |
|
||||
| Export-Syntax | `export default`, `export {...}` |
|
||||
| Dateiendung `.js` | **.js** nur mit `"type": "module"` |
|
||||
| `.mjs` | explizit ESM |
|
||||
| `__dirname`, `__filename` | ❌ nicht vorhanden, nur via `import.meta.url` |
|
||||
| Dynamische Imports | ✅ `await import('...')` |
|
||||
| Tree Shaking | ✅ möglich |
|
||||
| Browser-kompatibel | ✅ nativ |
|
||||
| CommonJS-Interop | ❗ mit Einschränkungen (`createRequire`) |
|
||||
|
||||
---
|
||||
|
||||
### ⚠️ Besonderheiten und Stolperfallen
|
||||
|
||||
| Problem | Lösung |
|
||||
| --------------------------------------------- | ------------------------------------------- |
|
||||
| ❌ `__dirname`/`__filename` fehlen | nutze `import.meta.url` + `fileURLToPath()` |
|
||||
| ❌ `require()` nicht verfügbar | verwende `import`, oder `createRequire()` |
|
||||
| ❌ `.js` muss beim Import angegeben werden | z. B. `import './utils.js'` |
|
||||
| ❌ viele alte Pakete sind nicht ESM-kompatibel | ggf. CommonJS verwenden |
|
||||
|
||||
---
|
||||
|
||||
### ✅ Fazit ESM
|
||||
|
||||
> **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:
|
||||
|
||||
- neue Projekte startest,
|
||||
- moderne Toolchains nutzt,
|
||||
- oder langfristige Kompatibilität willst.
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
## 🌐 CommonJS-Konfiguration CJS (Alternative)
|
||||
|
||||
### 📦 Was ist CommonJS?
|
||||
|
||||
**CommonJS (CJS)** ist das ursprüngliche Modulsystem von Node.js:
|
||||
|
||||
- verwendet `require()` zum Importieren
|
||||
- verwendet `module.exports` oder `exports` zum Exportieren
|
||||
- keine native Unterstützung für `import`/`export`
|
||||
- funktioniert nur in Node.js (nicht im Browser ohne Bundler)
|
||||
|
||||
```js
|
||||
// CommonJS-Stil
|
||||
const fs = require('fs');
|
||||
module.exports = { read: fs.readFileSync };
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### ✅ Wann kann/sollte/muss man **CommonJS** verwenden?
|
||||
|
||||
#### 🟢 **Du kannst CJS verwenden**, wenn
|
||||
|
||||
- du ein CLI-Tool oder Node.js-Skript erstellst
|
||||
- du maximale **Kompatibilität** ohne ESM-Komplikationen willst
|
||||
- du keine modernen ESM-Features brauchst
|
||||
- du auf Build-Tools verzichtest und direkt `.js`-Dateien startest
|
||||
|
||||
#### 🟡 **Du solltest CJS verwenden**, wenn
|
||||
|
||||
| Situation | Grund |
|
||||
| ------------------------------------------------------------------- | ------------------------------------------------------ |
|
||||
| 🔄 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 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 möchtest `.js`-Dateien ohne `.mjs` oder `type: module` nutzen | CommonJS macht keine Vorgaben für Dateiendungen |
|
||||
|
||||
#### 🔴 **Du musst CJS verwenden**, wenn
|
||||
|
||||
- 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)
|
||||
- du `require()` oder dynamisches Laden (`require(dynamicPath)`) verwendest, was in ESM nicht geht
|
||||
|
||||
---
|
||||
|
||||
### ⚙️ TypeScript-Konfiguration für CJS
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "CommonJS",
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Und in der `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
||||
```
|
||||
|
||||
**Hinweis:** Das `"type"`-Feld ist für Node wichtig, nicht für TypeScript.
|
||||
|
||||
---
|
||||
|
||||
### 📌 Merkmale von CommonJS
|
||||
|
||||
| Merkmal | CommonJS |
|
||||
| ------------------------- | -------------------------- |
|
||||
| Import-Syntax | `require()` |
|
||||
| Export-Syntax | `module.exports = …` |
|
||||
| Dateiendung | `.js` (keine `.mjs` nötig) |
|
||||
| Direkt ausführbar | ✅ Ohne zusätzliche Flags |
|
||||
| `__dirname`, `__filename` | ✅ verfügbar |
|
||||
| Browserkompatibilität | ❌ Nur mit Bundler möglich |
|
||||
| Dynamische Importe | ✅ `require(dynamicPath)` |
|
||||
| Tree Shaking | ❌ nicht möglich |
|
||||
|
||||
---
|
||||
|
||||
### ✅ Fazit CommonJS
|
||||
|
||||
> **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.**
|
||||
|
||||
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
|
||||
|
||||
- **Neue Projekte:** Nutze ESM mit `"type": "module"`
|
||||
- **Bestehende Tools nutzen `require()`?** Dann CJS
|
||||
- **Browser + Node gemeinsam nutzen?** ESM-only + klare Trennung von `shared/`, `client/`, `server/`
|
||||
- **Tooling wie Vite, Nuxt, Webpack?** Immer ESM
|
||||
|
||||
---
|
||||
|
||||
## 📁 Dateiendungen in Node.js
|
||||
|
||||
| Dateiendung | Verhalten |
|
||||
| ----------- | ------------------- |
|
||||
| `.js` | Hängt von `type` ab |
|
||||
| `.mjs` | Immer ESM |
|
||||
| `.cjs` | Immer CommonJS |
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Typische Fehler vermeiden
|
||||
|
||||
- **`SyntaxError: Cannot use import statement outside a module`**
|
||||
→ `type` fehlt in `package.json`
|
||||
|
||||
- **`Cannot find module` bei relativen Imports**
|
||||
→ `.js` fehlt am Ende beim ESM-Import
|
||||
|
||||
- **`__dirname` ist not defined**
|
||||
→ Du nutzt ESM, verwende `import.meta.url`
|
||||
|
||||
---
|
||||
|
||||
## 🚀 CLI-Build-Tipps (tsc)
|
||||
|
||||
```bash
|
||||
npx tsc # Kompiliert Projekt laut tsconfig.json
|
||||
chmod +x dist/index.js # Macht CLI-Datei ausführbar
|
||||
```
|
||||
|
||||
Header für CLI-Datei:
|
||||
|
||||
```ts
|
||||
#!/usr/bin/env node
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📍 Weiterführende Themen
|
||||
|
||||
- Dual-Exports für NPM (ESM + CJS gleichzeitig)
|
||||
- "exports"-Feld in `package.json`
|
||||
- Tools wie `tsup`, `vite`, `esbuild` als Alternativen zu `tsc`
|
||||
- Einstieg in CLI-Tools: `commander`, `yargs`, `chalk`, `ora`
|
||||
# Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration
|
||||
|
||||
## ✨ 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.
|
||||
|
||||
## Inhalt
|
||||
|
||||
- [Einstieg in JavaScript-Dialekte und TypeScript-Konfiguration](#einstieg-in-javascript-dialekte-und-typescript-konfiguration)
|
||||
- [✨ Ziel dieses Dokuments](#-ziel-dieses-dokuments)
|
||||
- [Inhalt](#inhalt)
|
||||
- [🔢 Begriffe erklärt](#-begriffe-erklärt)
|
||||
- [JavaScript-Dialekte (Modulsysteme)](#javascript-dialekte-modulsysteme)
|
||||
- [Was ist TypeScript?](#was-ist-typescript)
|
||||
- [🔍 Wann verwende ich was?](#-wann-verwende-ich-was)
|
||||
- [🔧 TypeScript richtig konfigurieren](#-typescript-richtig-konfigurieren)
|
||||
- [📦 Was ist ESM?](#-was-ist-esm)
|
||||
- [✅ Wann kann/sollte/muss man **ESM** verwenden?](#-wann-kannsolltemuss-man-esm-verwenden)
|
||||
- [🟢 **Du kannst ESM verwenden**, wenn](#-du-kannst-esm-verwenden-wenn)
|
||||
- [🟡 **Du solltest ESM verwenden**, wenn](#-du-solltest-esm-verwenden-wenn)
|
||||
- [🔴 **Du musst ESM verwenden**, wenn](#-du-musst-esm-verwenden-wenn)
|
||||
- [⚙️ TypeScript-Konfiguration für ESM](#️-typescript-konfiguration-für-esm)
|
||||
- [📌 Merkmale von ESM](#-merkmale-von-esm)
|
||||
- [⚠️ Besonderheiten und Stolperfallen](#️-besonderheiten-und-stolperfallen)
|
||||
- [✅ Fazit ESM](#-fazit-esm)
|
||||
- [🌐 CommonJS-Konfiguration CJS (Alternative)](#-commonjs-konfiguration-cjs-alternative)
|
||||
- [📦 Was ist CommonJS?](#-was-ist-commonjs)
|
||||
- [✅ Wann kann/sollte/muss man **CommonJS** verwenden?](#-wann-kannsolltemuss-man-commonjs-verwenden)
|
||||
- [🟢 **Du kannst CJS verwenden**, wenn](#-du-kannst-cjs-verwenden-wenn)
|
||||
- [🟡 **Du solltest CJS verwenden**, wenn](#-du-solltest-cjs-verwenden-wenn)
|
||||
- [🔴 **Du musst CJS verwenden**, wenn](#-du-musst-cjs-verwenden-wenn)
|
||||
- [⚙️ TypeScript-Konfiguration für CJS](#️-typescript-konfiguration-für-cjs)
|
||||
- [📌 Merkmale von CommonJS](#-merkmale-von-commonjs)
|
||||
- [✅ Fazit CommonJS](#-fazit-commonjs)
|
||||
- [📄 Fazit: Empfehlungen](#-fazit-empfehlungen)
|
||||
- [📁 Dateiendungen in Node.js](#-dateiendungen-in-nodejs)
|
||||
- [⚠️ Typische Fehler vermeiden](#️-typische-fehler-vermeiden)
|
||||
- [🚀 CLI-Build-Tipps (tsc)](#-cli-build-tipps-tsc)
|
||||
- [📍 Weiterführende Themen](#-weiterführende-themen)
|
||||
|
||||
---
|
||||
|
||||
## 🔢 Begriffe erklärt
|
||||
|
||||
### JavaScript-Dialekte (Modulsysteme)
|
||||
|
||||
| Name | Kürzel | Typ | Verwendung heute |
|
||||
| ------------------ | ------ | ----------- | ----------------------- |
|
||||
| CommonJS | CJS | `require()` | Ältere Node.js-Projekte |
|
||||
| ECMAScript Modules | ESM | `import` | Browser, moderne Tools |
|
||||
|
||||
- **CommonJS:** Nutzt `require()` und `module.exports`. Standard bis Node 12.
|
||||
- **ESM:** Nutzt `import`/`export`. Standard im Browser und in Node ab Version 14+.
|
||||
|
||||
### Was ist TypeScript?
|
||||
|
||||
TypeScript ist eine statisch typisierte Obermenge von JavaScript, die zu normalem JS kompiliert wird.
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Wann verwende ich was?
|
||||
|
||||
| Ziel | Modulformat | Empfehlung | Grund |
|
||||
| -------------------------- | ------------ | -------------- | ------------------------------------------ |
|
||||
| 📅 Moderne Webanwendung | ESM | Ja | Browser erwartet ESM |
|
||||
| 📄 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 |
|
||||
| 🔌 Electron Renderer | ESM | Ja (Pflicht) | Chromium-only, kein CJS |
|
||||
| 🔁 Vite/Webpack-Projekt | ESM | Ja | Toolchain basiert auf ESM |
|
||||
|
||||
---
|
||||
|
||||
## 🔧 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.
|
||||
|
||||
---
|
||||
|
||||
### 📦 Was ist ESM?
|
||||
|
||||
**ESM (ECMAScript Modules)** ist das moderne Modulsystem von JavaScript:
|
||||
|
||||
- verwendet `import`/`export`-Syntax
|
||||
- wird nativ von allen modernen Browsern und Node.js (ab v14+) unterstützt
|
||||
- ist Standard in allen modernen JS-Toolchains (Vite, Webpack, esbuild, etc.)
|
||||
|
||||
```js
|
||||
// ESM-Stil
|
||||
import fs from 'node:fs/promises';
|
||||
export function read(path) {
|
||||
return fs.readFile(path, 'utf-8');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### ✅ Wann kann/sollte/muss man **ESM** verwenden?
|
||||
|
||||
#### 🟢 **Du kannst ESM verwenden**, wenn
|
||||
|
||||
- du mit **modernen Node.js-Versionen (v16+)** arbeitest
|
||||
- du ein **Frontend-Tool** oder ein **Browser-kompatibles Projekt** baust
|
||||
- du Tree-Shaking oder Dynamic `import()` nutzen willst
|
||||
- du Typkonsistenz mit dem Browser willst (gleiche Syntax wie dort)
|
||||
|
||||
#### 🟡 **Du solltest ESM verwenden**, wenn
|
||||
|
||||
| Situation | Grund |
|
||||
| ------------------------------------------------------------------- | ---------------------------- |
|
||||
| 🌐 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 willst `import()` dynamisch verwenden | Nur in ESM verfügbar |
|
||||
| 📚 Du schreibst eine wiederverwendbare Bibliothek für neue Projekte | Zukunftssicherheit |
|
||||
| 🧩 Du verwendest Deno, Bun oder moderne Plattformen | ESM only |
|
||||
|
||||
#### 🔴 **Du musst ESM verwenden**, wenn
|
||||
|
||||
- du im **Browser** arbeitest (ohne Bundler) → dort ist `import` Pflicht
|
||||
- du in **Electron-Renderer-Prozessen** arbeitest
|
||||
- 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`)
|
||||
|
||||
---
|
||||
|
||||
### ⚙️ TypeScript-Konfiguration für ESM
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Und in der `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
```
|
||||
|
||||
**Wichtig:** Ohne `"type": "module"` behandelt Node deine `.js`-Dateien **nicht als ESM**, sondern als CommonJS.
|
||||
|
||||
---
|
||||
|
||||
### 📌 Merkmale von ESM
|
||||
|
||||
| Merkmal | ESM |
|
||||
| ------------------------- | -------------------------------------------- |
|
||||
| Import-Syntax | `import`, `export` |
|
||||
| Export-Syntax | `export default`, `export {...}` |
|
||||
| Dateiendung `.js` | **.js** nur mit `"type": "module"` |
|
||||
| `.mjs` | explizit ESM |
|
||||
| `__dirname`, `__filename` | ❌ nicht vorhanden, nur via `import.meta.url` |
|
||||
| Dynamische Imports | ✅ `await import('...')` |
|
||||
| Tree Shaking | ✅ möglich |
|
||||
| Browser-kompatibel | ✅ nativ |
|
||||
| CommonJS-Interop | ❗ mit Einschränkungen (`createRequire`) |
|
||||
|
||||
---
|
||||
|
||||
### ⚠️ Besonderheiten und Stolperfallen
|
||||
|
||||
| Problem | Lösung |
|
||||
| --------------------------------------------- | ------------------------------------------- |
|
||||
| ❌ `__dirname`/`__filename` fehlen | nutze `import.meta.url` + `fileURLToPath()` |
|
||||
| ❌ `require()` nicht verfügbar | verwende `import`, oder `createRequire()` |
|
||||
| ❌ `.js` muss beim Import angegeben werden | z. B. `import './utils.js'` |
|
||||
| ❌ viele alte Pakete sind nicht ESM-kompatibel | ggf. CommonJS verwenden |
|
||||
|
||||
---
|
||||
|
||||
### ✅ Fazit ESM
|
||||
|
||||
> **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:
|
||||
|
||||
- neue Projekte startest,
|
||||
- moderne Toolchains nutzt,
|
||||
- oder langfristige Kompatibilität willst.
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
## 🌐 CommonJS-Konfiguration CJS (Alternative)
|
||||
|
||||
### 📦 Was ist CommonJS?
|
||||
|
||||
**CommonJS (CJS)** ist das ursprüngliche Modulsystem von Node.js:
|
||||
|
||||
- verwendet `require()` zum Importieren
|
||||
- verwendet `module.exports` oder `exports` zum Exportieren
|
||||
- keine native Unterstützung für `import`/`export`
|
||||
- funktioniert nur in Node.js (nicht im Browser ohne Bundler)
|
||||
|
||||
```js
|
||||
// CommonJS-Stil
|
||||
const fs = require('fs');
|
||||
module.exports = { read: fs.readFileSync };
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### ✅ Wann kann/sollte/muss man **CommonJS** verwenden?
|
||||
|
||||
#### 🟢 **Du kannst CJS verwenden**, wenn
|
||||
|
||||
- du ein CLI-Tool oder Node.js-Skript erstellst
|
||||
- du maximale **Kompatibilität** ohne ESM-Komplikationen willst
|
||||
- du keine modernen ESM-Features brauchst
|
||||
- du auf Build-Tools verzichtest und direkt `.js`-Dateien startest
|
||||
|
||||
#### 🟡 **Du solltest CJS verwenden**, wenn
|
||||
|
||||
| Situation | Grund |
|
||||
| ------------------------------------------------------------------- | ------------------------------------------------------ |
|
||||
| 🔄 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 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 möchtest `.js`-Dateien ohne `.mjs` oder `type: module` nutzen | CommonJS macht keine Vorgaben für Dateiendungen |
|
||||
|
||||
#### 🔴 **Du musst CJS verwenden**, wenn
|
||||
|
||||
- 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)
|
||||
- du `require()` oder dynamisches Laden (`require(dynamicPath)`) verwendest, was in ESM nicht geht
|
||||
|
||||
---
|
||||
|
||||
### ⚙️ TypeScript-Konfiguration für CJS
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "CommonJS",
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Und in der `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
||||
```
|
||||
|
||||
**Hinweis:** Das `"type"`-Feld ist für Node wichtig, nicht für TypeScript.
|
||||
|
||||
---
|
||||
|
||||
### 📌 Merkmale von CommonJS
|
||||
|
||||
| Merkmal | CommonJS |
|
||||
| ------------------------- | -------------------------- |
|
||||
| Import-Syntax | `require()` |
|
||||
| Export-Syntax | `module.exports = …` |
|
||||
| Dateiendung | `.js` (keine `.mjs` nötig) |
|
||||
| Direkt ausführbar | ✅ Ohne zusätzliche Flags |
|
||||
| `__dirname`, `__filename` | ✅ verfügbar |
|
||||
| Browserkompatibilität | ❌ Nur mit Bundler möglich |
|
||||
| Dynamische Importe | ✅ `require(dynamicPath)` |
|
||||
| Tree Shaking | ❌ nicht möglich |
|
||||
|
||||
---
|
||||
|
||||
### ✅ Fazit CommonJS
|
||||
|
||||
> **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.**
|
||||
|
||||
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
|
||||
|
||||
- **Neue Projekte:** Nutze ESM mit `"type": "module"`
|
||||
- **Bestehende Tools nutzen `require()`?** Dann CJS
|
||||
- **Browser + Node gemeinsam nutzen?** ESM-only + klare Trennung von `shared/`, `client/`, `server/`
|
||||
- **Tooling wie Vite, Nuxt, Webpack?** Immer ESM
|
||||
|
||||
---
|
||||
|
||||
## 📁 Dateiendungen in Node.js
|
||||
|
||||
| Dateiendung | Verhalten |
|
||||
| ----------- | ------------------- |
|
||||
| `.js` | Hängt von `type` ab |
|
||||
| `.mjs` | Immer ESM |
|
||||
| `.cjs` | Immer CommonJS |
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Typische Fehler vermeiden
|
||||
|
||||
- **`SyntaxError: Cannot use import statement outside a module`**
|
||||
→ `type` fehlt in `package.json`
|
||||
|
||||
- **`Cannot find module` bei relativen Imports**
|
||||
→ `.js` fehlt am Ende beim ESM-Import
|
||||
|
||||
- **`__dirname` ist not defined**
|
||||
→ Du nutzt ESM, verwende `import.meta.url`
|
||||
|
||||
---
|
||||
|
||||
## 🚀 CLI-Build-Tipps (tsc)
|
||||
|
||||
```bash
|
||||
npx tsc # Kompiliert Projekt laut tsconfig.json
|
||||
chmod +x dist/index.js # Macht CLI-Datei ausführbar
|
||||
```
|
||||
|
||||
Header für CLI-Datei:
|
||||
|
||||
```ts
|
||||
#!/usr/bin/env node
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📍 Weiterführende Themen
|
||||
|
||||
- Dual-Exports für NPM (ESM + CJS gleichzeitig)
|
||||
- "exports"-Feld in `package.json`
|
||||
- Tools wie `tsup`, `vite`, `esbuild` als Alternativen zu `tsc`
|
||||
- Einstieg in CLI-Tools: `commander`, `yargs`, `chalk`, `ora`
|
||||
|
@ -1,64 +1,64 @@
|
||||
# Gewindetabellen
|
||||
|
||||
## 📏 **Praxis-Gewindetabelle (zöllig, G = BSPP)**
|
||||
|
||||
| Gewindebezeichnung | ⌀ Außengewinde (mm) | ⌀ Innengewinde (mm) | Typische Anwendung |
|
||||
| ------------------ | ------------------- | ------------------- | ---------------------------------- |
|
||||
| **G 1/8"** | \~9,7 mm | \~8,5 mm | Druckluft, Manometer |
|
||||
| **G 1/4"** | \~13,2 mm | \~11,5 mm | Kleingeräte, Kaffeemaschinen |
|
||||
| **G 3/8"** | \~16,6 mm | \~14,5 mm | Geräteventile, Mini-Zulaufschlauch |
|
||||
| **G 1/2"** | \~20,95 mm | \~18,6 mm | Wasserhahn, Spülarmatur |
|
||||
| **G 3/4"** | \~26,4 mm | \~24,0 mm | Waschmaschine, Gartenschlauch |
|
||||
| **G 1"** | \~33,25 mm | \~30,3 mm | Gartenwasserleitungen, Heizkreise |
|
||||
| **G 1 1/4"** | \~41,9 mm | \~38,8 mm | Hausanschluss, Regenwassernutzung |
|
||||
|
||||
---
|
||||
|
||||
### 📌 Hinweise
|
||||
|
||||
- Die Werte sind **gemittelte Praxiswerte**. Es gibt leichte Toleranzen je nach Hersteller.
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
---
|
||||
|
||||
## 📏 **Bohrtabelle für metrische ISO-Regelgewinde (M-Gewinde nach DIN 13-1)**
|
||||
|
||||
| Gewinde | Steigung (mm) | Kernloch-Ø (mm) (Bohrerdurchmesser) | Hinweis |
|
||||
| ------- | ------------- | ----------------------------------- | ---------------------- |
|
||||
| M1 | 0.25 | 0.75 | selten, Feinmechanik |
|
||||
| M1.2 | 0.25 | 0.95 | z. B. Elektronik |
|
||||
| M1.6 | 0.35 | 1.25 | sehr fein |
|
||||
| M2 | 0.4 | 1.6 | Standard M2 |
|
||||
| M2.5 | 0.45 | 2.05 | beliebt bei Modellbau |
|
||||
| M3 | 0.5 | 2.5 | sehr verbreitet |
|
||||
| M4 | 0.7 | 3.3 | Klassiker |
|
||||
| M5 | 0.8 | 4.2 | oft bei Maschinen |
|
||||
| M6 | 1.0 | 5.0 | Standardgröße |
|
||||
| M7 | 1.0 | 6.0 | eher selten |
|
||||
| M8 | 1.25 | 6.8 | Standard M8 |
|
||||
| M9 | 1.25 | 7.8 | Sondermaß |
|
||||
| M10 | 1.5 | 8.5 | Maschinenbau |
|
||||
| M11 | 1.5 | 9.5 | selten |
|
||||
| M12 | 1.75 | 10.2 | oft für tragende Teile |
|
||||
|
||||
---
|
||||
|
||||
### 📌 Hinweise Bohrtabelle
|
||||
|
||||
- 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).
|
||||
- Bei harter Werkstoffwahl ggf. Spiralbohrer vorher anspitzen oder mit Zentrierbohrer vorbohren.
|
||||
|
||||
---
|
||||
|
||||
### 🧰 Beispiel zur Borhtabelle
|
||||
|
||||
Du willst ein **M6-Gewinde** schneiden? → **5,0 mm Bohrer** nehmen → dann Gewindebohrer M6 einsetzen.
|
||||
|
||||
---
|
||||
# Gewindetabellen
|
||||
|
||||
## 📏 **Praxis-Gewindetabelle (zöllig, G = BSPP)**
|
||||
|
||||
| Gewindebezeichnung | ⌀ Außengewinde (mm) | ⌀ Innengewinde (mm) | Typische Anwendung |
|
||||
| ------------------ | ------------------- | ------------------- | ---------------------------------- |
|
||||
| **G 1/8"** | \~9,7 mm | \~8,5 mm | Druckluft, Manometer |
|
||||
| **G 1/4"** | \~13,2 mm | \~11,5 mm | Kleingeräte, Kaffeemaschinen |
|
||||
| **G 3/8"** | \~16,6 mm | \~14,5 mm | Geräteventile, Mini-Zulaufschlauch |
|
||||
| **G 1/2"** | \~20,95 mm | \~18,6 mm | Wasserhahn, Spülarmatur |
|
||||
| **G 3/4"** | \~26,4 mm | \~24,0 mm | Waschmaschine, Gartenschlauch |
|
||||
| **G 1"** | \~33,25 mm | \~30,3 mm | Gartenwasserleitungen, Heizkreise |
|
||||
| **G 1 1/4"** | \~41,9 mm | \~38,8 mm | Hausanschluss, Regenwassernutzung |
|
||||
|
||||
---
|
||||
|
||||
### 📌 Hinweise
|
||||
|
||||
- Die Werte sind **gemittelte Praxiswerte**. Es gibt leichte Toleranzen je nach Hersteller.
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
---
|
||||
|
||||
## 📏 **Bohrtabelle für metrische ISO-Regelgewinde (M-Gewinde nach DIN 13-1)**
|
||||
|
||||
| Gewinde | Steigung (mm) | Kernloch-Ø (mm) (Bohrerdurchmesser) | Hinweis |
|
||||
| ------- | ------------- | ----------------------------------- | ---------------------- |
|
||||
| M1 | 0.25 | 0.75 | selten, Feinmechanik |
|
||||
| M1.2 | 0.25 | 0.95 | z. B. Elektronik |
|
||||
| M1.6 | 0.35 | 1.25 | sehr fein |
|
||||
| M2 | 0.4 | 1.6 | Standard M2 |
|
||||
| M2.5 | 0.45 | 2.05 | beliebt bei Modellbau |
|
||||
| M3 | 0.5 | 2.5 | sehr verbreitet |
|
||||
| M4 | 0.7 | 3.3 | Klassiker |
|
||||
| M5 | 0.8 | 4.2 | oft bei Maschinen |
|
||||
| M6 | 1.0 | 5.0 | Standardgröße |
|
||||
| M7 | 1.0 | 6.0 | eher selten |
|
||||
| M8 | 1.25 | 6.8 | Standard M8 |
|
||||
| M9 | 1.25 | 7.8 | Sondermaß |
|
||||
| M10 | 1.5 | 8.5 | Maschinenbau |
|
||||
| M11 | 1.5 | 9.5 | selten |
|
||||
| M12 | 1.75 | 10.2 | oft für tragende Teile |
|
||||
|
||||
---
|
||||
|
||||
### 📌 Hinweise Bohrtabelle
|
||||
|
||||
- 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).
|
||||
- Bei harter Werkstoffwahl ggf. Spiralbohrer vorher anspitzen oder mit Zentrierbohrer vorbohren.
|
||||
|
||||
---
|
||||
|
||||
### 🧰 Beispiel zur Borhtabelle
|
||||
|
||||
Du willst ein **M6-Gewinde** schneiden? → **5,0 mm Bohrer** nehmen → dann Gewindebohrer M6 einsetzen.
|
||||
|
||||
---
|
||||
|
@ -1,108 +1,108 @@
|
||||
# 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)
|
||||
- [🧩 Problemstellung](#-problemstellung)
|
||||
- [🧠 Ursache](#-ursache)
|
||||
- [✅ Lösung](#-lösung)
|
||||
- [📍 Schritt-für-Schritt-Anleitung in Plesk:](#-schritt-für-schritt-anleitung-in-plesk)
|
||||
- [🔎 Test](#-test)
|
||||
- [🔁 Danach](#-danach)
|
||||
- [✅ Status: **Funktioniert**](#-status-funktioniert)
|
||||
|
||||
## 🧩 Problemstellung
|
||||
|
||||
Bei der Ausstellung eines SSL/TLS-Zertifikats für `gamingblogs.de` in Plesk trat folgender Fehler auf:
|
||||
|
||||
```text
|
||||
|
||||
Let's Encrypt-SSL/TLS-Zertifikat konnte nicht ausgestellt werden.
|
||||
Detail: Timeout during connect (likely firewall problem)
|
||||
|
||||
```
|
||||
|
||||
Trotz funktionierendem Webserver und anderen Domains auf dem gleichen Server schlug die Zertifikatsanforderung fehl.
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Ursache
|
||||
|
||||
Let's Encrypt konnte die Validierungs-URL
|
||||
|
||||
```text
|
||||
|
||||
[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.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Lösung
|
||||
|
||||
Damit Let's Encrypt den Challenge-Pfad über HTTP erreichen kann, muss der HTTPS-Redirect **ausgenommen werden**.
|
||||
|
||||
### 📍 Schritt-für-Schritt-Anleitung in Plesk:
|
||||
|
||||
1. Öffne **Plesk**
|
||||
2. Navigiere zu
|
||||
`Websites & Domains → gamingblogs.de → Apache & nginx-Einstellungen`
|
||||
3. Scrolle zu **"Zusätzliche Apache-Anweisungen"**
|
||||
4. Trage Folgendes in **beide Felder (HTTP und HTTPS)** ein:
|
||||
|
||||
```apache
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_URI} ^/\.well-known/acme-challenge/ [NC]
|
||||
RewriteRule ^ - [L]
|
||||
</IfModule>
|
||||
```
|
||||
|
||||
5. Falls ein HTTP-zu-HTTPS-Redirect aktiv ist, ergänze **nur im HTTP-Feld**:
|
||||
|
||||
```apache
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_URI} ^/\.well-known/acme-challenge/ [NC]
|
||||
RewriteRule ^ - [L]
|
||||
RewriteCond %{HTTPS} off
|
||||
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
||||
</IfModule>
|
||||
```
|
||||
|
||||
6. Speichern und warten, bis Plesk die Konfiguration neu lädt
|
||||
|
||||
---
|
||||
|
||||
## 🔎 Test
|
||||
|
||||
Vom externen System:
|
||||
|
||||
```bash
|
||||
curl -I http://gamingblogs.de/.well-known/acme-challenge/test
|
||||
```
|
||||
|
||||
**Erwartetes Ergebnis:**
|
||||
|
||||
```http
|
||||
HTTP/1.1 404 Not Found
|
||||
```
|
||||
|
||||
⚠️ Kein Redirect auf HTTPS, kein Timeout → Let's Encrypt kann jetzt validieren.
|
||||
|
||||
---
|
||||
|
||||
## 🔁 Danach
|
||||
|
||||
In Plesk:
|
||||
|
||||
1. Zurück zu `Websites & Domains → gamingblogs.de`
|
||||
2. Auf **"SSL/TLS-Zertifikat" (Let's Encrypt)** klicken
|
||||
3. Zertifikat neu **beantragen**
|
||||
4. Erfolgreiche Ausstellung wird bestätigt
|
||||
|
||||
---
|
||||
|
||||
## ✅ Status: **Funktioniert**
|
||||
|
||||
Datum der Umsetzung: 2025-05-22
|
||||
# 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)
|
||||
- [🧩 Problemstellung](#-problemstellung)
|
||||
- [🧠 Ursache](#-ursache)
|
||||
- [✅ Lösung](#-lösung)
|
||||
- [📍 Schritt-für-Schritt-Anleitung in Plesk:](#-schritt-für-schritt-anleitung-in-plesk)
|
||||
- [🔎 Test](#-test)
|
||||
- [🔁 Danach](#-danach)
|
||||
- [✅ Status: **Funktioniert**](#-status-funktioniert)
|
||||
|
||||
## 🧩 Problemstellung
|
||||
|
||||
Bei der Ausstellung eines SSL/TLS-Zertifikats für `gamingblogs.de` in Plesk trat folgender Fehler auf:
|
||||
|
||||
```text
|
||||
|
||||
Let's Encrypt-SSL/TLS-Zertifikat konnte nicht ausgestellt werden.
|
||||
Detail: Timeout during connect (likely firewall problem)
|
||||
|
||||
```
|
||||
|
||||
Trotz funktionierendem Webserver und anderen Domains auf dem gleichen Server schlug die Zertifikatsanforderung fehl.
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Ursache
|
||||
|
||||
Let's Encrypt konnte die Validierungs-URL
|
||||
|
||||
```text
|
||||
|
||||
[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.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Lösung
|
||||
|
||||
Damit Let's Encrypt den Challenge-Pfad über HTTP erreichen kann, muss der HTTPS-Redirect **ausgenommen werden**.
|
||||
|
||||
### 📍 Schritt-für-Schritt-Anleitung in Plesk:
|
||||
|
||||
1. Öffne **Plesk**
|
||||
2. Navigiere zu
|
||||
`Websites & Domains → gamingblogs.de → Apache & nginx-Einstellungen`
|
||||
3. Scrolle zu **"Zusätzliche Apache-Anweisungen"**
|
||||
4. Trage Folgendes in **beide Felder (HTTP und HTTPS)** ein:
|
||||
|
||||
```apache
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_URI} ^/\.well-known/acme-challenge/ [NC]
|
||||
RewriteRule ^ - [L]
|
||||
</IfModule>
|
||||
```
|
||||
|
||||
5. Falls ein HTTP-zu-HTTPS-Redirect aktiv ist, ergänze **nur im HTTP-Feld**:
|
||||
|
||||
```apache
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_URI} ^/\.well-known/acme-challenge/ [NC]
|
||||
RewriteRule ^ - [L]
|
||||
RewriteCond %{HTTPS} off
|
||||
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
||||
</IfModule>
|
||||
```
|
||||
|
||||
6. Speichern und warten, bis Plesk die Konfiguration neu lädt
|
||||
|
||||
---
|
||||
|
||||
## 🔎 Test
|
||||
|
||||
Vom externen System:
|
||||
|
||||
```bash
|
||||
curl -I http://gamingblogs.de/.well-known/acme-challenge/test
|
||||
```
|
||||
|
||||
**Erwartetes Ergebnis:**
|
||||
|
||||
```http
|
||||
HTTP/1.1 404 Not Found
|
||||
```
|
||||
|
||||
⚠️ Kein Redirect auf HTTPS, kein Timeout → Let's Encrypt kann jetzt validieren.
|
||||
|
||||
---
|
||||
|
||||
## 🔁 Danach
|
||||
|
||||
In Plesk:
|
||||
|
||||
1. Zurück zu `Websites & Domains → gamingblogs.de`
|
||||
2. Auf **"SSL/TLS-Zertifikat" (Let's Encrypt)** klicken
|
||||
3. Zertifikat neu **beantragen**
|
||||
4. Erfolgreiche Ausstellung wird bestätigt
|
||||
|
||||
---
|
||||
|
||||
## ✅ Status: **Funktioniert**
|
||||
|
||||
Datum der Umsetzung: 2025-05-22
|
@ -1,52 +1,52 @@
|
||||
# Plesk ausgesperrt bei Rechnerwechsel
|
||||
|
||||
## Inhalt
|
||||
|
||||
- [Plesk ausgesperrt bei Rechnerwechsel](#plesk-ausgesperrt-bei-rechnerwechsel)
|
||||
- [Inhalt](#inhalt)
|
||||
- [Problembeschreibung](#problembeschreibung)
|
||||
- [Workarround](#workarround)
|
||||
- [Nachhaltige Lösung des Problems](#nachhaltige-lösung-des-problems)
|
||||
|
||||
## 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.
|
||||
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.
|
||||
Um mich wieder einloggen zu können, muss ich die Session auf dem Server von hand aus der Datenbank löschen.
|
||||
|
||||
### Workarround
|
||||
|
||||
**Plesk Version:** Plesk Obsidian Web Admin Edition 18.0.70
|
||||
|
||||
Bei Plesk gibt es manchmal die gloreiche Meldung:
|
||||
|
||||
> Sie konnten nicht angemeldet werden.
|
||||
> **Ein anderer Benutzer mit demselben Benutzernamen (benutzername) ist bereits bei Plesk angemeldet.**
|
||||
|
||||
Ärgerlich wenn das gerade der Adminzugang ist.
|
||||
Falls Du gerade noch SSH Zugang hast dann:
|
||||
|
||||
login und wechsel zum root, anschliessend:
|
||||
|
||||
```bash
|
||||
plesk db "DELETE FROM sessions WHERE login = 'admin';"
|
||||
```
|
||||
|
||||
**oder**
|
||||
|
||||
```bash
|
||||
mysql -uadmin -p$(cat /etc/psa/.psa.shadow) psa -e "DELETE FROM sessions WHERE login = 'admin';"
|
||||
```
|
||||
|
||||
anschliessend:
|
||||
|
||||
```bash
|
||||
systemctl restart psa
|
||||
```
|
||||
|
||||
und dann ganz normal Login wie gewohnt.
|
||||
|
||||
### Nachhaltige Lösung des Problems
|
||||
|
||||
aktuell nicht bekannt!
|
||||
# Plesk ausgesperrt bei Rechnerwechsel
|
||||
|
||||
## Inhalt
|
||||
|
||||
- [Plesk ausgesperrt bei Rechnerwechsel](#plesk-ausgesperrt-bei-rechnerwechsel)
|
||||
- [Inhalt](#inhalt)
|
||||
- [Problembeschreibung](#problembeschreibung)
|
||||
- [Workarround](#workarround)
|
||||
- [Nachhaltige Lösung des Problems](#nachhaltige-lösung-des-problems)
|
||||
|
||||
## 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.
|
||||
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.
|
||||
Um mich wieder einloggen zu können, muss ich die Session auf dem Server von hand aus der Datenbank löschen.
|
||||
|
||||
### Workarround
|
||||
|
||||
**Plesk Version:** Plesk Obsidian Web Admin Edition 18.0.70
|
||||
|
||||
Bei Plesk gibt es manchmal die gloreiche Meldung:
|
||||
|
||||
> Sie konnten nicht angemeldet werden.
|
||||
> **Ein anderer Benutzer mit demselben Benutzernamen (benutzername) ist bereits bei Plesk angemeldet.**
|
||||
|
||||
Ärgerlich wenn das gerade der Adminzugang ist.
|
||||
Falls Du gerade noch SSH Zugang hast dann:
|
||||
|
||||
login und wechsel zum root, anschliessend:
|
||||
|
||||
```bash
|
||||
plesk db "DELETE FROM sessions WHERE login = 'admin';"
|
||||
```
|
||||
|
||||
**oder**
|
||||
|
||||
```bash
|
||||
mysql -uadmin -p$(cat /etc/psa/.psa.shadow) psa -e "DELETE FROM sessions WHERE login = 'admin';"
|
||||
```
|
||||
|
||||
anschliessend:
|
||||
|
||||
```bash
|
||||
systemctl restart psa
|
||||
```
|
||||
|
||||
und dann ganz normal Login wie gewohnt.
|
||||
|
||||
### Nachhaltige Lösung des Problems
|
||||
|
||||
aktuell nicht bekannt!
|
||||
|
@ -1,152 +1,152 @@
|
||||
# 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.
|
||||
|
||||
---
|
||||
|
||||
## Ziel
|
||||
|
||||
Ein USB-Stick oder Offline-Verzeichnis mit:
|
||||
|
||||
- Rust-Installer (offlinefähig)
|
||||
- Visual Studio Build Tools (komplett inkl. MSVC)
|
||||
- Optional: vorkompilierte Ziel-Toolchains
|
||||
|
||||
---
|
||||
|
||||
## 1. Rust Offline-Installer vorbereiten
|
||||
|
||||
### 1.1 Rustup Offline-Installer besorgen
|
||||
|
||||
Gehe auf:
|
||||
|
||||
https://forge.rust-lang.org/infra/release-archives.html
|
||||
|
||||
Lade von dort:
|
||||
|
||||
- `rust-<version>-x86_64-pc-windows-msvc.msi`
|
||||
- `cargo-<version>-x86_64-pc-windows-msvc.msi` (optional)
|
||||
|
||||
Oder direkt über:
|
||||
|
||||
https://static.rust-lang.org/dist/
|
||||
|
||||
### 1.2 Installation ohne Internet
|
||||
|
||||
Auf dem Zielrechner:
|
||||
|
||||
- Führe `.msi`-Datei lokal aus
|
||||
- Setze den `Path` manuell oder automatisch via Skript
|
||||
|
||||
---
|
||||
|
||||
## 2. Visual Studio Build Tools offline installieren
|
||||
|
||||
### 2.1 Installer herunterladen
|
||||
|
||||
Lade den **Visual Studio Installer** von:
|
||||
|
||||
https://visualstudio.microsoft.com/de/visual-cpp-build-tools/
|
||||
|
||||
Starte dann:
|
||||
|
||||
```cmd
|
||||
vs_BuildTools.exe --layout C:\VSOffline --lang de-DE
|
||||
```
|
||||
|
||||
Dieser Befehl erstellt einen vollständigen Offline-Installer im Verzeichnis `C:\VSOffline`.
|
||||
|
||||
### 2.2 Auswahl der Workloads
|
||||
|
||||
Wähle beim interaktiven Download (GUI oder CLI):
|
||||
|
||||
- **C++ Build Tools**
|
||||
- Workload-Komponenten:
|
||||
- MSVC v14.x (x64/x86)
|
||||
- Windows 10/11 SDK
|
||||
- CMake-Tools (optional)
|
||||
|
||||
> 💡 Achtung: Download-Größe ca. 4–6 GB!
|
||||
|
||||
### 2.3 Installation auf Zielsystem (Offline)
|
||||
|
||||
Auf dem Zielrechner:
|
||||
|
||||
```cmd
|
||||
C:\VSOffline\vs_BuildTools.exe --noweb --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --quiet --wait
|
||||
```
|
||||
|
||||
Alternativ über `vs_setup.exe`, je nach Version.
|
||||
|
||||
---
|
||||
|
||||
## 3. Optional: Toolchains, Crates & Targets vorbereiten
|
||||
|
||||
Falls du zusätzliche Targets (z. B. Linux oder ARM) brauchst:
|
||||
|
||||
### 3.1 Ziel-Toolchain lokal laden
|
||||
|
||||
```cmd
|
||||
rustup target add x86_64-unknown-linux-gnu --print
|
||||
```
|
||||
|
||||
Lade die `.tar.gz` von:
|
||||
|
||||
https://static.rust-lang.org/dist/
|
||||
|
||||
Speichere diese im `dist/`-Ordner und installiere offline via:
|
||||
|
||||
```cmd
|
||||
rustup toolchain link <name> <pfad_zur_toolchain>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Automatisierung via USB-Stick
|
||||
|
||||
### Dateistruktur auf Stick
|
||||
|
||||
```text
|
||||
USB-STICK/
|
||||
├── rust/
|
||||
│ └── rust-1.xx.x-x86_64-pc-windows-msvc.msi
|
||||
├── vsbuildtools/
|
||||
│ └── setup + Offline-Daten
|
||||
├── install.cmd
|
||||
```
|
||||
|
||||
### Beispiel `install.cmd`
|
||||
|
||||
```cmd
|
||||
@echo off
|
||||
echo [1/2] Installiere Rust...
|
||||
start /wait rust\rust-*.msi
|
||||
|
||||
echo [2/2] Installiere Visual Studio Build Tools...
|
||||
start /wait vsbuildtools\vs_BuildTools.exe --noweb --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --quiet --wait
|
||||
|
||||
echo Fertig. Bitte PC neu starten!
|
||||
pause
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Validierung
|
||||
|
||||
Nach der Offline-Installation auf Zielsystem:
|
||||
|
||||
```cmd
|
||||
cargo new testprojekt
|
||||
cd testprojekt
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
Ergebnis:
|
||||
|
||||
target\release\testprojekt.exe
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
# 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.
|
||||
|
||||
---
|
||||
|
||||
## Ziel
|
||||
|
||||
Ein USB-Stick oder Offline-Verzeichnis mit:
|
||||
|
||||
- Rust-Installer (offlinefähig)
|
||||
- Visual Studio Build Tools (komplett inkl. MSVC)
|
||||
- Optional: vorkompilierte Ziel-Toolchains
|
||||
|
||||
---
|
||||
|
||||
## 1. Rust Offline-Installer vorbereiten
|
||||
|
||||
### 1.1 Rustup Offline-Installer besorgen
|
||||
|
||||
Gehe auf:
|
||||
|
||||
https://forge.rust-lang.org/infra/release-archives.html
|
||||
|
||||
Lade von dort:
|
||||
|
||||
- `rust-<version>-x86_64-pc-windows-msvc.msi`
|
||||
- `cargo-<version>-x86_64-pc-windows-msvc.msi` (optional)
|
||||
|
||||
Oder direkt über:
|
||||
|
||||
https://static.rust-lang.org/dist/
|
||||
|
||||
### 1.2 Installation ohne Internet
|
||||
|
||||
Auf dem Zielrechner:
|
||||
|
||||
- Führe `.msi`-Datei lokal aus
|
||||
- Setze den `Path` manuell oder automatisch via Skript
|
||||
|
||||
---
|
||||
|
||||
## 2. Visual Studio Build Tools offline installieren
|
||||
|
||||
### 2.1 Installer herunterladen
|
||||
|
||||
Lade den **Visual Studio Installer** von:
|
||||
|
||||
https://visualstudio.microsoft.com/de/visual-cpp-build-tools/
|
||||
|
||||
Starte dann:
|
||||
|
||||
```cmd
|
||||
vs_BuildTools.exe --layout C:\VSOffline --lang de-DE
|
||||
```
|
||||
|
||||
Dieser Befehl erstellt einen vollständigen Offline-Installer im Verzeichnis `C:\VSOffline`.
|
||||
|
||||
### 2.2 Auswahl der Workloads
|
||||
|
||||
Wähle beim interaktiven Download (GUI oder CLI):
|
||||
|
||||
- **C++ Build Tools**
|
||||
- Workload-Komponenten:
|
||||
- MSVC v14.x (x64/x86)
|
||||
- Windows 10/11 SDK
|
||||
- CMake-Tools (optional)
|
||||
|
||||
> 💡 Achtung: Download-Größe ca. 4–6 GB!
|
||||
|
||||
### 2.3 Installation auf Zielsystem (Offline)
|
||||
|
||||
Auf dem Zielrechner:
|
||||
|
||||
```cmd
|
||||
C:\VSOffline\vs_BuildTools.exe --noweb --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --quiet --wait
|
||||
```
|
||||
|
||||
Alternativ über `vs_setup.exe`, je nach Version.
|
||||
|
||||
---
|
||||
|
||||
## 3. Optional: Toolchains, Crates & Targets vorbereiten
|
||||
|
||||
Falls du zusätzliche Targets (z. B. Linux oder ARM) brauchst:
|
||||
|
||||
### 3.1 Ziel-Toolchain lokal laden
|
||||
|
||||
```cmd
|
||||
rustup target add x86_64-unknown-linux-gnu --print
|
||||
```
|
||||
|
||||
Lade die `.tar.gz` von:
|
||||
|
||||
https://static.rust-lang.org/dist/
|
||||
|
||||
Speichere diese im `dist/`-Ordner und installiere offline via:
|
||||
|
||||
```cmd
|
||||
rustup toolchain link <name> <pfad_zur_toolchain>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Automatisierung via USB-Stick
|
||||
|
||||
### Dateistruktur auf Stick
|
||||
|
||||
```text
|
||||
USB-STICK/
|
||||
├── rust/
|
||||
│ └── rust-1.xx.x-x86_64-pc-windows-msvc.msi
|
||||
├── vsbuildtools/
|
||||
│ └── setup + Offline-Daten
|
||||
├── install.cmd
|
||||
```
|
||||
|
||||
### Beispiel `install.cmd`
|
||||
|
||||
```cmd
|
||||
@echo off
|
||||
echo [1/2] Installiere Rust...
|
||||
start /wait rust\rust-*.msi
|
||||
|
||||
echo [2/2] Installiere Visual Studio Build Tools...
|
||||
start /wait vsbuildtools\vs_BuildTools.exe --noweb --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --quiet --wait
|
||||
|
||||
echo Fertig. Bitte PC neu starten!
|
||||
pause
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Validierung
|
||||
|
||||
Nach der Offline-Installation auf Zielsystem:
|
||||
|
||||
```cmd
|
||||
cargo new testprojekt
|
||||
cd testprojekt
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
Ergebnis:
|
||||
|
||||
target\release\testprojekt.exe
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
|
@ -1,152 +1,152 @@
|
||||
# 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.
|
||||
|
||||
## Inhalt
|
||||
|
||||
- [Rust-Toolchain mit MSVC unter Windows einrichten](#rust-toolchain-mit-msvc-unter-windows-einrichten)
|
||||
- [Inhalt](#inhalt)
|
||||
- [Voraussetzungen](#voraussetzungen)
|
||||
- [1. Rust installieren](#1-rust-installieren)
|
||||
- [2. Visual Studio Build Tools installieren](#2-visual-studio-build-tools-installieren)
|
||||
- [Schritt-für-Schritt](#schritt-für-schritt)
|
||||
- [3. Umgebungsvariablen setzen (optional)](#3-umgebungsvariablen-setzen-optional)
|
||||
- [4. Beispielprojekt erstellen](#4-beispielprojekt-erstellen)
|
||||
- [5. Projekt kompilieren](#5-projekt-kompilieren)
|
||||
- [Debug-Build (schnell, nicht optimiert)](#debug-build-schnell-nicht-optimiert)
|
||||
- [Release-Build (optimiert, kleine `.exe`)](#release-build-optimiert-kleine-exe)
|
||||
- [6. Optional: `.exe` testen](#6-optional-exe-testen)
|
||||
- [7. Troubleshooting](#7-troubleshooting)
|
||||
- [8. Alternative: Toolchain in einem Offline-Installer vorbereiten](#8-alternative-toolchain-in-einem-offline-installer-vorbereiten)
|
||||
- [Zusammenfassung](#zusammenfassung)
|
||||
- [Weiterführende Themen](#weiterführende-themen)
|
||||
|
||||
---
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
- Windows 10 oder 11 (64 Bit)
|
||||
- Administratorrechte
|
||||
- Mindestens 2 GB freier Speicherplatz
|
||||
|
||||
## 1. Rust installieren
|
||||
|
||||
Lade das offizielle Rust-Installationsprogramm herunter und führe es aus:
|
||||
|
||||
<https://rustup.rs>
|
||||
|
||||
Beim Setup:
|
||||
|
||||
- **Toolchain wählen**: `default host triple: x86_64-pc-windows-msvc`
|
||||
- Folge dem Assistenten, um `rustc`, `cargo` und `rustup` zu installieren.
|
||||
|
||||
Verifiziere die Installation:
|
||||
|
||||
```shell
|
||||
rustc --version
|
||||
cargo --version
|
||||
```
|
||||
|
||||
## 2. Visual Studio Build Tools installieren
|
||||
|
||||
Die Rust-Toolchain mit MSVC benötigt den **"C++ Build Tools"**-Teil von Visual Studio.
|
||||
|
||||
### Schritt-für-Schritt
|
||||
|
||||
1. Lade den **Visual Studio Installer**:
|
||||
- <https://visualstudio.microsoft.com/de/visual-cpp-build-tools/>
|
||||
|
||||
2. Wähle bei der Installation:
|
||||
- ✅ **C++ Build Tools**
|
||||
- Und in der rechten Spalte:
|
||||
- ✅ "MSVC v14.x - VS 2022 C++ x64/x86-Buildtools"
|
||||
- ✅ "Windows 10 SDK" oder "Windows 11 SDK" (je nach Zielsystem)
|
||||
- ✅ "C++ CMake-Tools für Windows" (optional für CMake-Projekte)
|
||||
|
||||
3. Installiere alles und starte das System neu, falls verlangt.
|
||||
|
||||
## 3. Umgebungsvariablen setzen (optional)
|
||||
|
||||
Falls du die Buildtools über Kommandozeile verwenden willst, öffne:
|
||||
|
||||
```cmd
|
||||
"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.
|
||||
|
||||
## 4. Beispielprojekt erstellen
|
||||
|
||||
```cmd
|
||||
cargo new hello_world
|
||||
cd hello_world
|
||||
```
|
||||
|
||||
Beispielcode in `src/main.rs`:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
println!("Hallo Welt – kompiliert mit MSVC!");
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Projekt kompilieren
|
||||
|
||||
### Debug-Build (schnell, nicht optimiert)
|
||||
|
||||
```cmd
|
||||
cargo build
|
||||
```
|
||||
|
||||
### Release-Build (optimiert, kleine `.exe`)
|
||||
|
||||
```cmd
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
Die fertige `.exe` liegt unter:
|
||||
|
||||
.\target\release\hello_world.exe
|
||||
|
||||
## 6. Optional: `.exe` testen
|
||||
|
||||
```cmd
|
||||
.\target\release\hello_world.exe
|
||||
```
|
||||
|
||||
## 7. Troubleshooting
|
||||
|
||||
- **Fehlermeldung `link.exe not found`?**
|
||||
→ Build-Tools sind nicht korrekt installiert (siehe Schritt 2)
|
||||
|
||||
- **Fehlermeldung zu fehlendem SDK?**
|
||||
→ Stelle sicher, dass du das passende Windows SDK mit installiert hast
|
||||
|
||||
- **MSVC und GNU Toolchain gleichzeitig installiert?**
|
||||
→ Du kannst über `rustup` zwischen beiden wechseln:
|
||||
|
||||
```cmd
|
||||
rustup show
|
||||
rustup default stable-x86_64-pc-windows-msvc
|
||||
```
|
||||
|
||||
## 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).
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Komponente | Aufgabe |
|
||||
|------------------|----------------------------------|
|
||||
| Rustup | Verwaltung von Toolchains |
|
||||
| Cargo | Buildsystem und Paketmanager |
|
||||
| MSVC Build Tools | C++-Compiler/Linker für Windows |
|
||||
| `vcvars64.bat` | Aktiviert Build-Umgebung |
|
||||
| `cargo build` | Erstellt `.exe` mit Rust und MSVC |
|
||||
|
||||
## Weiterführende Themen
|
||||
|
||||
- Einbindung von Ressourcen und Icons in die `.exe`
|
||||
- Verwendung von `cc`/`bindgen` für C-Bindings
|
||||
- Cross-Kompilierung mit `x86_64-pc-windows-gnu` oder Linux-Zielsystemen
|
||||
- Automatisierter Build via Makefile oder PowerShell
|
||||
# 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.
|
||||
|
||||
## Inhalt
|
||||
|
||||
- [Rust-Toolchain mit MSVC unter Windows einrichten](#rust-toolchain-mit-msvc-unter-windows-einrichten)
|
||||
- [Inhalt](#inhalt)
|
||||
- [Voraussetzungen](#voraussetzungen)
|
||||
- [1. Rust installieren](#1-rust-installieren)
|
||||
- [2. Visual Studio Build Tools installieren](#2-visual-studio-build-tools-installieren)
|
||||
- [Schritt-für-Schritt](#schritt-für-schritt)
|
||||
- [3. Umgebungsvariablen setzen (optional)](#3-umgebungsvariablen-setzen-optional)
|
||||
- [4. Beispielprojekt erstellen](#4-beispielprojekt-erstellen)
|
||||
- [5. Projekt kompilieren](#5-projekt-kompilieren)
|
||||
- [Debug-Build (schnell, nicht optimiert)](#debug-build-schnell-nicht-optimiert)
|
||||
- [Release-Build (optimiert, kleine `.exe`)](#release-build-optimiert-kleine-exe)
|
||||
- [6. Optional: `.exe` testen](#6-optional-exe-testen)
|
||||
- [7. Troubleshooting](#7-troubleshooting)
|
||||
- [8. Alternative: Toolchain in einem Offline-Installer vorbereiten](#8-alternative-toolchain-in-einem-offline-installer-vorbereiten)
|
||||
- [Zusammenfassung](#zusammenfassung)
|
||||
- [Weiterführende Themen](#weiterführende-themen)
|
||||
|
||||
---
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
- Windows 10 oder 11 (64 Bit)
|
||||
- Administratorrechte
|
||||
- Mindestens 2 GB freier Speicherplatz
|
||||
|
||||
## 1. Rust installieren
|
||||
|
||||
Lade das offizielle Rust-Installationsprogramm herunter und führe es aus:
|
||||
|
||||
<https://rustup.rs>
|
||||
|
||||
Beim Setup:
|
||||
|
||||
- **Toolchain wählen**: `default host triple: x86_64-pc-windows-msvc`
|
||||
- Folge dem Assistenten, um `rustc`, `cargo` und `rustup` zu installieren.
|
||||
|
||||
Verifiziere die Installation:
|
||||
|
||||
```shell
|
||||
rustc --version
|
||||
cargo --version
|
||||
```
|
||||
|
||||
## 2. Visual Studio Build Tools installieren
|
||||
|
||||
Die Rust-Toolchain mit MSVC benötigt den **"C++ Build Tools"**-Teil von Visual Studio.
|
||||
|
||||
### Schritt-für-Schritt
|
||||
|
||||
1. Lade den **Visual Studio Installer**:
|
||||
- <https://visualstudio.microsoft.com/de/visual-cpp-build-tools/>
|
||||
|
||||
2. Wähle bei der Installation:
|
||||
- ✅ **C++ Build Tools**
|
||||
- Und in der rechten Spalte:
|
||||
- ✅ "MSVC v14.x - VS 2022 C++ x64/x86-Buildtools"
|
||||
- ✅ "Windows 10 SDK" oder "Windows 11 SDK" (je nach Zielsystem)
|
||||
- ✅ "C++ CMake-Tools für Windows" (optional für CMake-Projekte)
|
||||
|
||||
3. Installiere alles und starte das System neu, falls verlangt.
|
||||
|
||||
## 3. Umgebungsvariablen setzen (optional)
|
||||
|
||||
Falls du die Buildtools über Kommandozeile verwenden willst, öffne:
|
||||
|
||||
```cmd
|
||||
"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.
|
||||
|
||||
## 4. Beispielprojekt erstellen
|
||||
|
||||
```cmd
|
||||
cargo new hello_world
|
||||
cd hello_world
|
||||
```
|
||||
|
||||
Beispielcode in `src/main.rs`:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
println!("Hallo Welt – kompiliert mit MSVC!");
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Projekt kompilieren
|
||||
|
||||
### Debug-Build (schnell, nicht optimiert)
|
||||
|
||||
```cmd
|
||||
cargo build
|
||||
```
|
||||
|
||||
### Release-Build (optimiert, kleine `.exe`)
|
||||
|
||||
```cmd
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
Die fertige `.exe` liegt unter:
|
||||
|
||||
.\target\release\hello_world.exe
|
||||
|
||||
## 6. Optional: `.exe` testen
|
||||
|
||||
```cmd
|
||||
.\target\release\hello_world.exe
|
||||
```
|
||||
|
||||
## 7. Troubleshooting
|
||||
|
||||
- **Fehlermeldung `link.exe not found`?**
|
||||
→ Build-Tools sind nicht korrekt installiert (siehe Schritt 2)
|
||||
|
||||
- **Fehlermeldung zu fehlendem SDK?**
|
||||
→ Stelle sicher, dass du das passende Windows SDK mit installiert hast
|
||||
|
||||
- **MSVC und GNU Toolchain gleichzeitig installiert?**
|
||||
→ Du kannst über `rustup` zwischen beiden wechseln:
|
||||
|
||||
```cmd
|
||||
rustup show
|
||||
rustup default stable-x86_64-pc-windows-msvc
|
||||
```
|
||||
|
||||
## 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).
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Komponente | Aufgabe |
|
||||
|------------------|----------------------------------|
|
||||
| Rustup | Verwaltung von Toolchains |
|
||||
| Cargo | Buildsystem und Paketmanager |
|
||||
| MSVC Build Tools | C++-Compiler/Linker für Windows |
|
||||
| `vcvars64.bat` | Aktiviert Build-Umgebung |
|
||||
| `cargo build` | Erstellt `.exe` mit Rust und MSVC |
|
||||
|
||||
## Weiterführende Themen
|
||||
|
||||
- Einbindung von Ressourcen und Icons in die `.exe`
|
||||
- Verwendung von `cc`/`bindgen` für C-Bindings
|
||||
- Cross-Kompilierung mit `x86_64-pc-windows-gnu` oder Linux-Zielsystemen
|
||||
- Automatisierter Build via Makefile oder PowerShell
|
||||
|
158
dokus/webserver/nginx-proxy-manager-setup.md
Normal file
158
dokus/webserver/nginx-proxy-manager-setup.md
Normal 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.
|
@ -1,177 +1,177 @@
|
||||
# Einführung in die `desktop.ini`-Datei: Verwendung und Anpassung von Ordnern in Windows
|
||||
|
||||
*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.
|
||||
|
||||
## 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)
|
||||
- [Inhaltsverzeichnis](#inhaltsverzeichnis)
|
||||
- [Was ist die `desktop.ini`-Datei?](#was-ist-die-desktopini-datei)
|
||||
- [Grundlegende Struktur der `desktop.ini`](#grundlegende-struktur-der-desktopini)
|
||||
- [Wichtige Optionen und Attribute](#wichtige-optionen-und-attribute)
|
||||
- [Optionen in der `[General]`-Sektion](#optionen-in-der-general-sektion)
|
||||
- [Optionen in der `[View]`-Sektion](#optionen-in-der-view-sektion)
|
||||
- [Optionen in der `[Icon]`-Sektion](#optionen-in-der-icon-sektion)
|
||||
- [Optionen in der `[LocalizedFileNames]`-Sektion](#optionen-in-der-localizedfilenames-sektion)
|
||||
- [Optionen in der `[ShellClassInfo]`-Sektion](#optionen-in-der-shellclassinfo-sektion)
|
||||
- [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)
|
||||
- [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)
|
||||
- [Fazit](#fazit)
|
||||
|
||||
## 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.
|
||||
|
||||
## 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:
|
||||
|
||||
- `[General]`: Enthält grundlegende Informationen zum Ordner, wie den Namen und den Tooltip.
|
||||
- `[View]`: Steuert die Anzeigeeinstellungen des Ordners.
|
||||
- `[Icon]`: Definiert das Symbol des Ordners.
|
||||
- `[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.
|
||||
|
||||
## Wichtige Optionen und Attribute
|
||||
|
||||
### Optionen in der `[General]`-Sektion
|
||||
|
||||
- **`Name`**: Der Name des Ordners, der im Windows Explorer angezeigt wird.
|
||||
|
||||
```ini
|
||||
Name=Mein Ordner
|
||||
```
|
||||
|
||||
- **`InfoTip`**: Ein Tooltip, der angezeigt wird, wenn der Benutzer mit der Maus über den Ordner fährt.
|
||||
|
||||
```ini
|
||||
InfoTip=Dies ist ein wichtiger Ordner.
|
||||
```
|
||||
|
||||
### Optionen in der `[View]`-Sektion
|
||||
|
||||
- **`Mode`**: Bestimmt die Ansicht des Ordners. Mögliche Werte:
|
||||
- `0`: Liste
|
||||
- `1`: Details
|
||||
- `2`: Große Symbole
|
||||
- `3`: Kleine Symbole
|
||||
|
||||
```ini
|
||||
Mode=2 ; Setze den Ordner auf "Große Symbole"
|
||||
```
|
||||
|
||||
- **`FolderType`**: Bestimmt den Typ des Ordners, z. B. `Documents`, `Music`, `Pictures`.
|
||||
|
||||
```ini
|
||||
FolderType=Documents ; Ordnertyp auf Dokumente setzen
|
||||
```
|
||||
|
||||
- **`IconAreaImage`**: Setzt ein Hintergrundbild für den Ordnerbereich.
|
||||
|
||||
```ini
|
||||
IconAreaImage=C:\Bilder\Hintergrund.png
|
||||
```
|
||||
|
||||
### Optionen in der `[Icon]`-Sektion
|
||||
|
||||
- **`IconFile`**: Der Pfad zu einer Datei, die das Ordnersymbol enthält (z. B. `.ico`, `.dll`, `.exe`).
|
||||
|
||||
```ini
|
||||
IconFile=C:\Windows\System32\shell32.dll
|
||||
```
|
||||
|
||||
- **`IconIndex`**: Der Index des Symbols in der Datei, wenn mehrere Symbole in einer Datei vorhanden sind.
|
||||
|
||||
```ini
|
||||
IconIndex=5
|
||||
```
|
||||
|
||||
### Optionen in der `[LocalizedFileNames]`-Sektion
|
||||
|
||||
- **`@`**: Erlaubt die Anzeige von Ordnernamen in verschiedenen Sprachen.
|
||||
|
||||
```ini
|
||||
[LocalizedFileNames]
|
||||
@="Projektordner"
|
||||
```
|
||||
|
||||
### Optionen in der `[ShellClassInfo]`-Sektion
|
||||
|
||||
- **`NoSharing`**: Verhindert die Freigabe des Ordners über das Netzwerk.
|
||||
|
||||
```ini
|
||||
NoSharing=1 ; Verhindert die Netzwerkfreigabe
|
||||
```
|
||||
|
||||
- **`ConfirmFileOp`**: Steuert, ob eine Bestätigung beim Kopieren von Dateien erforderlich ist.
|
||||
|
||||
```ini
|
||||
ConfirmFileOp=0 ; Keine Bestätigung erforderlich
|
||||
```
|
||||
|
||||
- **`InfoTip`**: Eine zusätzliche Option zur Festlegung eines Tooltips.
|
||||
|
||||
```ini
|
||||
InfoTip=Dieser Ordner enthält Projektdateien.
|
||||
```
|
||||
|
||||
- **`IconFile` und `IconIndex`**: Wiederholung der Optionen zur Festlegung des Ordnersymbols.
|
||||
|
||||
```ini
|
||||
IconFile=C:\Windows\System32\shell32.dll
|
||||
IconIndex=5
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
Beispiel:
|
||||
|
||||
```ini
|
||||
; Dies ist ein Kommentar
|
||||
[.ShellClassInfo]
|
||||
IconFile=C:\Windows\System32\shell32.dll
|
||||
IconIndex=23
|
||||
```
|
||||
|
||||
## Die Bedeutung von Attributen und Rechten der `desktop.ini`
|
||||
|
||||
Die `desktop.ini`-Datei muss bestimmte **Dateiattribute** besitzen, damit sie korrekt funktioniert:
|
||||
|
||||
- **Schreibgeschützt (`+r`)**: Verhindert, dass die Datei überschrieben 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.
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
- **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`.
|
||||
|
||||
Die richtigen Attribute können alle auf einmal gesetzt werden, indem Sie den folgenden Befehl verwenden:
|
||||
|
||||
```cmd
|
||||
attrib +r +h +s desktop.ini
|
||||
```
|
||||
|
||||
## 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:
|
||||
|
||||
- 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.
|
||||
|
||||
## 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.
|
||||
# Einführung in die `desktop.ini`-Datei: Verwendung und Anpassung von Ordnern in Windows
|
||||
|
||||
*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.
|
||||
|
||||
## 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)
|
||||
- [Inhaltsverzeichnis](#inhaltsverzeichnis)
|
||||
- [Was ist die `desktop.ini`-Datei?](#was-ist-die-desktopini-datei)
|
||||
- [Grundlegende Struktur der `desktop.ini`](#grundlegende-struktur-der-desktopini)
|
||||
- [Wichtige Optionen und Attribute](#wichtige-optionen-und-attribute)
|
||||
- [Optionen in der `[General]`-Sektion](#optionen-in-der-general-sektion)
|
||||
- [Optionen in der `[View]`-Sektion](#optionen-in-der-view-sektion)
|
||||
- [Optionen in der `[Icon]`-Sektion](#optionen-in-der-icon-sektion)
|
||||
- [Optionen in der `[LocalizedFileNames]`-Sektion](#optionen-in-der-localizedfilenames-sektion)
|
||||
- [Optionen in der `[ShellClassInfo]`-Sektion](#optionen-in-der-shellclassinfo-sektion)
|
||||
- [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)
|
||||
- [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)
|
||||
- [Fazit](#fazit)
|
||||
|
||||
## 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.
|
||||
|
||||
## 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:
|
||||
|
||||
- `[General]`: Enthält grundlegende Informationen zum Ordner, wie den Namen und den Tooltip.
|
||||
- `[View]`: Steuert die Anzeigeeinstellungen des Ordners.
|
||||
- `[Icon]`: Definiert das Symbol des Ordners.
|
||||
- `[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.
|
||||
|
||||
## Wichtige Optionen und Attribute
|
||||
|
||||
### Optionen in der `[General]`-Sektion
|
||||
|
||||
- **`Name`**: Der Name des Ordners, der im Windows Explorer angezeigt wird.
|
||||
|
||||
```ini
|
||||
Name=Mein Ordner
|
||||
```
|
||||
|
||||
- **`InfoTip`**: Ein Tooltip, der angezeigt wird, wenn der Benutzer mit der Maus über den Ordner fährt.
|
||||
|
||||
```ini
|
||||
InfoTip=Dies ist ein wichtiger Ordner.
|
||||
```
|
||||
|
||||
### Optionen in der `[View]`-Sektion
|
||||
|
||||
- **`Mode`**: Bestimmt die Ansicht des Ordners. Mögliche Werte:
|
||||
- `0`: Liste
|
||||
- `1`: Details
|
||||
- `2`: Große Symbole
|
||||
- `3`: Kleine Symbole
|
||||
|
||||
```ini
|
||||
Mode=2 ; Setze den Ordner auf "Große Symbole"
|
||||
```
|
||||
|
||||
- **`FolderType`**: Bestimmt den Typ des Ordners, z. B. `Documents`, `Music`, `Pictures`.
|
||||
|
||||
```ini
|
||||
FolderType=Documents ; Ordnertyp auf Dokumente setzen
|
||||
```
|
||||
|
||||
- **`IconAreaImage`**: Setzt ein Hintergrundbild für den Ordnerbereich.
|
||||
|
||||
```ini
|
||||
IconAreaImage=C:\Bilder\Hintergrund.png
|
||||
```
|
||||
|
||||
### Optionen in der `[Icon]`-Sektion
|
||||
|
||||
- **`IconFile`**: Der Pfad zu einer Datei, die das Ordnersymbol enthält (z. B. `.ico`, `.dll`, `.exe`).
|
||||
|
||||
```ini
|
||||
IconFile=C:\Windows\System32\shell32.dll
|
||||
```
|
||||
|
||||
- **`IconIndex`**: Der Index des Symbols in der Datei, wenn mehrere Symbole in einer Datei vorhanden sind.
|
||||
|
||||
```ini
|
||||
IconIndex=5
|
||||
```
|
||||
|
||||
### Optionen in der `[LocalizedFileNames]`-Sektion
|
||||
|
||||
- **`@`**: Erlaubt die Anzeige von Ordnernamen in verschiedenen Sprachen.
|
||||
|
||||
```ini
|
||||
[LocalizedFileNames]
|
||||
@="Projektordner"
|
||||
```
|
||||
|
||||
### Optionen in der `[ShellClassInfo]`-Sektion
|
||||
|
||||
- **`NoSharing`**: Verhindert die Freigabe des Ordners über das Netzwerk.
|
||||
|
||||
```ini
|
||||
NoSharing=1 ; Verhindert die Netzwerkfreigabe
|
||||
```
|
||||
|
||||
- **`ConfirmFileOp`**: Steuert, ob eine Bestätigung beim Kopieren von Dateien erforderlich ist.
|
||||
|
||||
```ini
|
||||
ConfirmFileOp=0 ; Keine Bestätigung erforderlich
|
||||
```
|
||||
|
||||
- **`InfoTip`**: Eine zusätzliche Option zur Festlegung eines Tooltips.
|
||||
|
||||
```ini
|
||||
InfoTip=Dieser Ordner enthält Projektdateien.
|
||||
```
|
||||
|
||||
- **`IconFile` und `IconIndex`**: Wiederholung der Optionen zur Festlegung des Ordnersymbols.
|
||||
|
||||
```ini
|
||||
IconFile=C:\Windows\System32\shell32.dll
|
||||
IconIndex=5
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
Beispiel:
|
||||
|
||||
```ini
|
||||
; Dies ist ein Kommentar
|
||||
[.ShellClassInfo]
|
||||
IconFile=C:\Windows\System32\shell32.dll
|
||||
IconIndex=23
|
||||
```
|
||||
|
||||
## Die Bedeutung von Attributen und Rechten der `desktop.ini`
|
||||
|
||||
Die `desktop.ini`-Datei muss bestimmte **Dateiattribute** besitzen, damit sie korrekt funktioniert:
|
||||
|
||||
- **Schreibgeschützt (`+r`)**: Verhindert, dass die Datei überschrieben 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.
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
- **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`.
|
||||
|
||||
Die richtigen Attribute können alle auf einmal gesetzt werden, indem Sie den folgenden Befehl verwenden:
|
||||
|
||||
```cmd
|
||||
attrib +r +h +s desktop.ini
|
||||
```
|
||||
|
||||
## 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:
|
||||
|
||||
- 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.
|
||||
|
||||
## 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.
|
||||
|
1122
package-lock.json
generated
1122
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
48
package.json
48
package.json
@ -1,24 +1,24 @@
|
||||
{
|
||||
"name": "tools",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"link-collector": "./dist/index.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"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",
|
||||
"clean": "node ./tools/dist/fsdel.js ./tools/dist/collector/link_collector.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs": "^0.0.1-security",
|
||||
"path": "^0.12.7",
|
||||
"process": "^0.11.10",
|
||||
"typescript": "^5.8.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.15.29",
|
||||
"esbuild": "^0.25.5"
|
||||
}
|
||||
}
|
||||
{
|
||||
"name": "tools",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"link-collector": "./dist/index.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"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",
|
||||
"clean": "node ./tools/dist/fsdel.js ./tools/dist/collector/link_collector.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs": "^0.0.1-security",
|
||||
"path": "^0.12.7",
|
||||
"process": "^0.11.10",
|
||||
"typescript": "^5.8.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.15.29",
|
||||
"esbuild": "^0.25.5"
|
||||
}
|
||||
}
|
||||
|
60
scan.cmd
60
scan.cmd
@ -1,29 +1,31 @@
|
||||
@echo off
|
||||
REM ------------------------------------------------------------
|
||||
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 ------------------------------------------------------------
|
||||
|
||||
REM ==== KONFIGURATION =====
|
||||
set SCRIPT=tools\collector\link_collector.py
|
||||
set PYTHON=python
|
||||
REM ========================
|
||||
|
||||
chcp 65001 >nul
|
||||
|
||||
where %PYTHON% >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo ❌ Python wurde nicht gefunden.
|
||||
echo.
|
||||
echo Bitte installiere Python von:
|
||||
echo https://www.python.org/downloads/windows/
|
||||
echo.
|
||||
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
|
||||
@echo off
|
||||
REM ------------------------------------------------------------
|
||||
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
|
||||
REM Wird durch (./tools/collector/link_collector.py) und `npm run scan` abgeloest!
|
||||
REM ------------------------------------------------------------
|
||||
|
||||
REM ==== KONFIGURATION =====
|
||||
set SCRIPT=tools\collector\link_collector.py
|
||||
set PYTHON=python
|
||||
REM ========================
|
||||
|
||||
chcp 65001 >nul
|
||||
|
||||
where %PYTHON% >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo ❌ Python wurde nicht gefunden.
|
||||
echo.
|
||||
echo Bitte installiere Python von:
|
||||
echo https://www.python.org/downloads/windows/
|
||||
echo.
|
||||
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
|
||||
|
@ -1,16 +1,16 @@
|
||||
{
|
||||
// Verzeichnis relativ zum Script, das durchsucht wird
|
||||
"root_dirs": [
|
||||
"dokus"
|
||||
],
|
||||
|
||||
// Nur Dateien mit dieser Endung (wird erweitert)
|
||||
"extensions": [".md"],
|
||||
|
||||
// Zielpfad für die Linkausgabe (Markdown-Datei)
|
||||
"output_file": "README.md",
|
||||
|
||||
// Optional: Log für bereits verarbeitete Dateien. Dateien die dort
|
||||
// enthalten sind, werden nicht nochmals verabeitet.
|
||||
"processed_log": "processed.log"
|
||||
}
|
||||
{
|
||||
// Verzeichnis relativ zum Script, das durchsucht wird
|
||||
"root_dirs": [
|
||||
"dokus"
|
||||
],
|
||||
|
||||
// Nur Dateien mit dieser Endung (wird erweitert)
|
||||
"extensions": [".md"],
|
||||
|
||||
// Zielpfad für die Linkausgabe (Markdown-Datei)
|
||||
"output_file": "README.md",
|
||||
|
||||
// Optional: Log für bereits verarbeitete Dateien. Dateien die dort
|
||||
// enthalten sind, werden nicht nochmals verabeitet.
|
||||
"processed_log": "processed.log"
|
||||
}
|
||||
|
@ -57,19 +57,19 @@ class ArgParser {
|
||||
return result;
|
||||
}
|
||||
static showHelp() {
|
||||
console.log(`
|
||||
(C) 2025 - Adam Skotarczak (ionivation.com)
|
||||
|
||||
🛈 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]
|
||||
|
||||
-s, --scan Kommagetrennte Liste von Verzeichnissen zum Durchsuchen (relativ zum Aufrufpfad)
|
||||
-x, --ignore Kommagetrennte Liste von Verzeichnissen, die ignoriert werden sollen
|
||||
--reset Löscht das Logfile 'processed.log' und beendet sich
|
||||
-h, --hilfe Zeigt diese Hilfe
|
||||
|
||||
Beispiel:
|
||||
ts-node link_collector.ts -s docs,notes -x "docs/alt"
|
||||
console.log(`
|
||||
(C) 2025 - Adam Skotarczak (ionivation.com)
|
||||
|
||||
🛈 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]
|
||||
|
||||
-s, --scan Kommagetrennte Liste von Verzeichnissen zum Durchsuchen (relativ zum Aufrufpfad)
|
||||
-x, --ignore Kommagetrennte Liste von Verzeichnissen, die ignoriert werden sollen
|
||||
--reset Löscht das Logfile 'processed.log' und beendet sich
|
||||
-h, --hilfe Zeigt diese Hilfe
|
||||
|
||||
Beispiel:
|
||||
ts-node link_collector.ts -s docs,notes -x "docs/alt"
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
@ -1,164 +1,164 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# Gibt das Verzeichnis zurück, in dem dieses Skript liegt
|
||||
def script_dir():
|
||||
return Path(__file__).parent.resolve()
|
||||
|
||||
# Lädt die JSONC-Konfiguration (Kommentare via // werden ignoriert)
|
||||
def load_config(filename="config.jsonc"):
|
||||
config_path = script_dir() / filename
|
||||
if not config_path.exists():
|
||||
print(" ⚠ Konfigurationsdatei nicht gefunden:", config_path)
|
||||
sys.exit(1)
|
||||
with open(config_path, encoding="utf-8") as f:
|
||||
# Entfernt //-Kommentare vor dem Parsen
|
||||
return json.loads("".join(line for line in f if not line.strip().startswith("//")))
|
||||
|
||||
# Parsen der Kommandozeilenargumente
|
||||
def parse_args():
|
||||
args = sys.argv[1:]
|
||||
parsed = {
|
||||
"scan": None, # Verzeichnisse zum Scannen (List[str])
|
||||
"ignore": [], # Verzeichnisse, die ignoriert werden sollen (List[str])
|
||||
"reset": False, # Setzt das Logfile zurück
|
||||
"hilfe": False, # Zeigt die Hilfe an
|
||||
}
|
||||
|
||||
# Argumente durchgehen und zuweisen
|
||||
while args:
|
||||
arg = args.pop(0)
|
||||
if arg in ("-h", "--hilfe"):
|
||||
parsed["hilfe"] = True
|
||||
elif arg == "--reset":
|
||||
parsed["reset"] = True
|
||||
elif arg in ("-s", "--scan") and args:
|
||||
parsed["scan"] = [entry.strip() for entry in args.pop(0).split(",") if entry.strip()]
|
||||
elif arg in ("-x", "--ignore") and args:
|
||||
parsed["ignore"] = [entry.strip() for entry in args.pop(0).split(",") if entry.strip()]
|
||||
else:
|
||||
print(f" ⚠ Unbekannter Parameter: {arg}")
|
||||
parsed["hilfe"] = True
|
||||
break
|
||||
|
||||
return parsed
|
||||
|
||||
# Ausgabe der Hilfetexte für CLI-Nutzer
|
||||
def show_help():
|
||||
print("""
|
||||
(C) 2025 - Adam Skotarczak (ionivation.com)
|
||||
|
||||
🛈 Tool das Verzeichnisse nach Markdown-Dateien durchsucht und diese an eine definierte Liste anhängt als Markdown-Link.
|
||||
Verwendung: python3 link_collector.py [OPTIONEN]
|
||||
|
||||
-s, --scan Kommagetrennte Liste von Verzeichnissen zum Durchsuchen (relativ zum Aufrufpfad)
|
||||
-x, --ignore Kommagetrennte Liste von Verzeichnissen, die ignoriert werden sollen
|
||||
--reset Löscht das Logfile 'processed.log' und beendet sich
|
||||
-h, --hilfe Zeigt diese Hilfe
|
||||
|
||||
Beispiel:
|
||||
python3 link_collector.py -s docs,notes -x "docs/alt"
|
||||
""")
|
||||
|
||||
# Generator: Findet Markdown-Dateien (rekursiv), ignoriert dabei definierte Pfade
|
||||
def find_md_files(root_dirs, ignore_dirs, extensions):
|
||||
for root in root_dirs:
|
||||
for dirpath, _, filenames in os.walk(root):
|
||||
# Ignorierpfade überspringen
|
||||
if any(str(Path(dirpath)).startswith(str(ignored)) for ignored in ignore_dirs):
|
||||
continue
|
||||
for fname in filenames:
|
||||
if any(fname.endswith(ext) for ext in extensions):
|
||||
yield Path(dirpath) / fname
|
||||
|
||||
# Extrahiert den ersten Markdown-Titel (# ...) als Linktext
|
||||
def extract_title(filepath):
|
||||
try:
|
||||
with open(filepath, encoding="utf-8") as f:
|
||||
for line in f:
|
||||
if line.strip().startswith("#"):
|
||||
return line.strip("# ").strip()
|
||||
except Exception as e:
|
||||
print(f"⚠ Fehler beim Lesen von {filepath}: {e}")
|
||||
# Fallback: Dateiname ohne Endung
|
||||
return filepath.stem
|
||||
|
||||
# Liest bereits verarbeitete Dateien aus dem Log (Pfadangaben im POSIX-Format)
|
||||
def load_processed(logfile):
|
||||
if not logfile.exists():
|
||||
return set()
|
||||
with open(logfile, encoding="utf-8") as f:
|
||||
# Vereinheitlichung auf POSIX-Konvention
|
||||
return set(Path(line.strip()).as_posix() for line in f)
|
||||
|
||||
# Hängt neue Markdown-Links ans Output-Dokument an
|
||||
def append_to_output(output_path, links):
|
||||
with open(output_path, "a", encoding="utf-8") as f:
|
||||
for line in links:
|
||||
f.write(line + "\n")
|
||||
|
||||
# Ergänzt das Logfile um neu verarbeitete Dateien (POSIX-Format)
|
||||
def update_processed(log_path, new_paths):
|
||||
with open(log_path, "a", encoding="utf-8") as f:
|
||||
for path in new_paths:
|
||||
f.write(path.as_posix() + "\n")
|
||||
|
||||
# Hauptfunktion mit gesamtem Ablauf
|
||||
def main():
|
||||
config = load_config()
|
||||
args = parse_args()
|
||||
|
||||
if args["hilfe"]:
|
||||
show_help()
|
||||
return
|
||||
|
||||
log_path = script_dir() / config.get("processed_log", "processed.log")
|
||||
|
||||
# Optionaler Reset des Logs
|
||||
if args["reset"]:
|
||||
if log_path.exists():
|
||||
log_path.unlink()
|
||||
print("🧹 Logfile gelöscht:", log_path)
|
||||
else:
|
||||
print("ℹ Logfile existierte nicht:", log_path)
|
||||
return
|
||||
|
||||
cwd = Path.cwd()
|
||||
output_file = cwd / config.get("output_file", "output.md")
|
||||
|
||||
# Verzeichnisse aus CLI oder Konfiguration
|
||||
root_dirs = args["scan"] or config.get("root_dirs", [])
|
||||
root_dirs = [Path(d).resolve() for d in root_dirs if d.strip()]
|
||||
ignore_dirs = [Path(x).resolve() for x in args["ignore"]]
|
||||
|
||||
extensions = config.get("extensions", [".md"])
|
||||
processed = load_processed(log_path)
|
||||
|
||||
new_links = []
|
||||
new_processed = []
|
||||
|
||||
# Dateien durchsuchen und neue Markdown-Dateien verlinken
|
||||
for md_file in find_md_files(root_dirs, ignore_dirs, extensions):
|
||||
if md_file.resolve() == output_file.resolve():
|
||||
continue # nicht sich selbst verlinken
|
||||
rel_path = md_file.relative_to(cwd)
|
||||
rel_path_posix = rel_path.as_posix()
|
||||
if rel_path_posix in processed:
|
||||
continue # bereits im Logfile
|
||||
title = extract_title(md_file)
|
||||
new_links.append(f"- [{title}]({rel_path_posix})")
|
||||
new_processed.append(rel_path)
|
||||
|
||||
# Ergebnisse schreiben
|
||||
if new_links:
|
||||
append_to_output(output_file, new_links)
|
||||
update_processed(log_path, new_processed)
|
||||
print(f"✔ {len(new_links)} neue Links hinzugefügt.")
|
||||
else:
|
||||
print(" ℹ Keine neuen Dateien gefunden.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# Gibt das Verzeichnis zurück, in dem dieses Skript liegt
|
||||
def script_dir():
|
||||
return Path(__file__).parent.resolve()
|
||||
|
||||
# Lädt die JSONC-Konfiguration (Kommentare via // werden ignoriert)
|
||||
def load_config(filename="config.jsonc"):
|
||||
config_path = script_dir() / filename
|
||||
if not config_path.exists():
|
||||
print(" ⚠ Konfigurationsdatei nicht gefunden:", config_path)
|
||||
sys.exit(1)
|
||||
with open(config_path, encoding="utf-8") as f:
|
||||
# Entfernt //-Kommentare vor dem Parsen
|
||||
return json.loads("".join(line for line in f if not line.strip().startswith("//")))
|
||||
|
||||
# Parsen der Kommandozeilenargumente
|
||||
def parse_args():
|
||||
args = sys.argv[1:]
|
||||
parsed = {
|
||||
"scan": None, # Verzeichnisse zum Scannen (List[str])
|
||||
"ignore": [], # Verzeichnisse, die ignoriert werden sollen (List[str])
|
||||
"reset": False, # Setzt das Logfile zurück
|
||||
"hilfe": False, # Zeigt die Hilfe an
|
||||
}
|
||||
|
||||
# Argumente durchgehen und zuweisen
|
||||
while args:
|
||||
arg = args.pop(0)
|
||||
if arg in ("-h", "--hilfe"):
|
||||
parsed["hilfe"] = True
|
||||
elif arg == "--reset":
|
||||
parsed["reset"] = True
|
||||
elif arg in ("-s", "--scan") and args:
|
||||
parsed["scan"] = [entry.strip() for entry in args.pop(0).split(",") if entry.strip()]
|
||||
elif arg in ("-x", "--ignore") and args:
|
||||
parsed["ignore"] = [entry.strip() for entry in args.pop(0).split(",") if entry.strip()]
|
||||
else:
|
||||
print(f" ⚠ Unbekannter Parameter: {arg}")
|
||||
parsed["hilfe"] = True
|
||||
break
|
||||
|
||||
return parsed
|
||||
|
||||
# Ausgabe der Hilfetexte für CLI-Nutzer
|
||||
def show_help():
|
||||
print("""
|
||||
(C) 2025 - Adam Skotarczak (ionivation.com)
|
||||
|
||||
🛈 Tool das Verzeichnisse nach Markdown-Dateien durchsucht und diese an eine definierte Liste anhängt als Markdown-Link.
|
||||
Verwendung: python3 link_collector.py [OPTIONEN]
|
||||
|
||||
-s, --scan Kommagetrennte Liste von Verzeichnissen zum Durchsuchen (relativ zum Aufrufpfad)
|
||||
-x, --ignore Kommagetrennte Liste von Verzeichnissen, die ignoriert werden sollen
|
||||
--reset Löscht das Logfile 'processed.log' und beendet sich
|
||||
-h, --hilfe Zeigt diese Hilfe
|
||||
|
||||
Beispiel:
|
||||
python3 link_collector.py -s docs,notes -x "docs/alt"
|
||||
""")
|
||||
|
||||
# Generator: Findet Markdown-Dateien (rekursiv), ignoriert dabei definierte Pfade
|
||||
def find_md_files(root_dirs, ignore_dirs, extensions):
|
||||
for root in root_dirs:
|
||||
for dirpath, _, filenames in os.walk(root):
|
||||
# Ignorierpfade überspringen
|
||||
if any(str(Path(dirpath)).startswith(str(ignored)) for ignored in ignore_dirs):
|
||||
continue
|
||||
for fname in filenames:
|
||||
if any(fname.endswith(ext) for ext in extensions):
|
||||
yield Path(dirpath) / fname
|
||||
|
||||
# Extrahiert den ersten Markdown-Titel (# ...) als Linktext
|
||||
def extract_title(filepath):
|
||||
try:
|
||||
with open(filepath, encoding="utf-8") as f:
|
||||
for line in f:
|
||||
if line.strip().startswith("#"):
|
||||
return line.strip("# ").strip()
|
||||
except Exception as e:
|
||||
print(f"⚠ Fehler beim Lesen von {filepath}: {e}")
|
||||
# Fallback: Dateiname ohne Endung
|
||||
return filepath.stem
|
||||
|
||||
# Liest bereits verarbeitete Dateien aus dem Log (Pfadangaben im POSIX-Format)
|
||||
def load_processed(logfile):
|
||||
if not logfile.exists():
|
||||
return set()
|
||||
with open(logfile, encoding="utf-8") as f:
|
||||
# Vereinheitlichung auf POSIX-Konvention
|
||||
return set(Path(line.strip()).as_posix() for line in f)
|
||||
|
||||
# Hängt neue Markdown-Links ans Output-Dokument an
|
||||
def append_to_output(output_path, links):
|
||||
with open(output_path, "a", encoding="utf-8") as f:
|
||||
for line in links:
|
||||
f.write(line + "\n")
|
||||
|
||||
# Ergänzt das Logfile um neu verarbeitete Dateien (POSIX-Format)
|
||||
def update_processed(log_path, new_paths):
|
||||
with open(log_path, "a", encoding="utf-8") as f:
|
||||
for path in new_paths:
|
||||
f.write(path.as_posix() + "\n")
|
||||
|
||||
# Hauptfunktion mit gesamtem Ablauf
|
||||
def main():
|
||||
config = load_config()
|
||||
args = parse_args()
|
||||
|
||||
if args["hilfe"]:
|
||||
show_help()
|
||||
return
|
||||
|
||||
log_path = script_dir() / config.get("processed_log", "processed.log")
|
||||
|
||||
# Optionaler Reset des Logs
|
||||
if args["reset"]:
|
||||
if log_path.exists():
|
||||
log_path.unlink()
|
||||
print("🧹 Logfile gelöscht:", log_path)
|
||||
else:
|
||||
print("ℹ Logfile existierte nicht:", log_path)
|
||||
return
|
||||
|
||||
cwd = Path.cwd()
|
||||
output_file = cwd / config.get("output_file", "output.md")
|
||||
|
||||
# Verzeichnisse aus CLI oder Konfiguration
|
||||
root_dirs = args["scan"] or config.get("root_dirs", [])
|
||||
root_dirs = [Path(d).resolve() for d in root_dirs if d.strip()]
|
||||
ignore_dirs = [Path(x).resolve() for x in args["ignore"]]
|
||||
|
||||
extensions = config.get("extensions", [".md"])
|
||||
processed = load_processed(log_path)
|
||||
|
||||
new_links = []
|
||||
new_processed = []
|
||||
|
||||
# Dateien durchsuchen und neue Markdown-Dateien verlinken
|
||||
for md_file in find_md_files(root_dirs, ignore_dirs, extensions):
|
||||
if md_file.resolve() == output_file.resolve():
|
||||
continue # nicht sich selbst verlinken
|
||||
rel_path = md_file.relative_to(cwd)
|
||||
rel_path_posix = rel_path.as_posix()
|
||||
if rel_path_posix in processed:
|
||||
continue # bereits im Logfile
|
||||
title = extract_title(md_file)
|
||||
new_links.append(f"- [{title}]({rel_path_posix})")
|
||||
new_processed.append(rel_path)
|
||||
|
||||
# Ergebnisse schreiben
|
||||
if new_links:
|
||||
append_to_output(output_file, new_links)
|
||||
update_processed(log_path, new_processed)
|
||||
print(f"✔ {len(new_links)} neue Links hinzugefügt.")
|
||||
else:
|
||||
print(" ℹ Keine neuen Dateien gefunden.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -1,13 +1,14 @@
|
||||
dokus/helix__editor_einfuehrung_de.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/mechanik/gewindetabellen.md
|
||||
dokus/js-ts/js-ts-dialekte.md
|
||||
dokus/git/git-remote-branch.md
|
||||
dokus/git/git-ssh-remote.md
|
||||
dokus/git/git-submodule-leitfaden.md
|
||||
dokus/git/git.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
|
||||
|
@ -1,16 +1,16 @@
|
||||
{
|
||||
// Verzeichnis relativ zum Script, das durchsucht wird
|
||||
"root_dirs": [
|
||||
"dokus"
|
||||
],
|
||||
|
||||
// Nur Dateien mit dieser Endung (wird erweitert)
|
||||
"extensions": [".md"],
|
||||
|
||||
// Zielpfad für die Linkausgabe (Markdown-Datei)
|
||||
"output_file": "README.md",
|
||||
|
||||
// Optional: Log für bereits verarbeitete Dateien. Dateien die dort
|
||||
// enthalten sind, werden nicht nochmals verabeitet.
|
||||
"processed_log": "processed.log"
|
||||
}
|
||||
{
|
||||
// Verzeichnis relativ zum Script, das durchsucht wird
|
||||
"root_dirs": [
|
||||
"dokus"
|
||||
],
|
||||
|
||||
// Nur Dateien mit dieser Endung (wird erweitert)
|
||||
"extensions": [".md"],
|
||||
|
||||
// Zielpfad für die Linkausgabe (Markdown-Datei)
|
||||
"output_file": "README.md",
|
||||
|
||||
// Optional: Log für bereits verarbeitete Dateien. Dateien die dort
|
||||
// enthalten sind, werden nicht nochmals verabeitet.
|
||||
"processed_log": "processed.log"
|
||||
}
|
||||
|
@ -1,225 +1,225 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname } from 'node:path';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
type Config = {
|
||||
root_dirs?: string[];
|
||||
output_file?: string;
|
||||
processed_log?: string;
|
||||
extensions?: string[];
|
||||
};
|
||||
|
||||
type Args = {
|
||||
scan: string[] | null;
|
||||
ignore: string[];
|
||||
reset: boolean;
|
||||
hilfe: boolean;
|
||||
};
|
||||
|
||||
class ScriptInfo {
|
||||
static dir(): string {
|
||||
return path.dirname(__filename);
|
||||
}
|
||||
|
||||
static cwd(): string {
|
||||
return process.cwd();
|
||||
}
|
||||
}
|
||||
|
||||
class ConfigLoader {
|
||||
static load(filename = 'config.jsonc'): Config {
|
||||
const configPath = path.join(ScriptInfo.dir(), filename);
|
||||
if (!fs.existsSync(configPath)) {
|
||||
console.error(` ⚠ Konfigurationsdatei nicht gefunden: ${configPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
const raw = fs.readFileSync(configPath, 'utf8');
|
||||
const clean = raw
|
||||
.split('\n')
|
||||
.filter(line => !line.trim().startsWith('//'))
|
||||
.join('');
|
||||
return JSON.parse(clean);
|
||||
}
|
||||
}
|
||||
|
||||
class ArgParser {
|
||||
static parse(): Args {
|
||||
const argv = process.argv.slice(2);
|
||||
const result: Args = { scan: null, ignore: [], reset: false, hilfe: false };
|
||||
|
||||
while (argv.length) {
|
||||
const arg = argv.shift();
|
||||
if (!arg) break;
|
||||
|
||||
if (arg === '-h' || arg === '--hilfe') {
|
||||
result.hilfe = true;
|
||||
} else if (arg === '--reset') {
|
||||
result.reset = true;
|
||||
} else if ((arg === '-s' || arg === '--scan') && argv.length) {
|
||||
result.scan = argv.shift()!.split(',').map(x => x.trim()).filter(Boolean);
|
||||
} else if ((arg === '-x' || arg === '--ignore') && argv.length) {
|
||||
result.ignore = argv.shift()!.split(',').map(x => x.trim()).filter(Boolean);
|
||||
} else {
|
||||
console.warn(` ⚠ Unbekannter Parameter: ${arg}`);
|
||||
result.hilfe = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static showHelp(): void {
|
||||
console.log(`
|
||||
(C) 2025 - Adam Skotarczak (ionivation.com)
|
||||
|
||||
🛈 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]
|
||||
|
||||
-s, --scan Kommagetrennte Liste von Verzeichnissen zum Durchsuchen (relativ zum Aufrufpfad)
|
||||
-x, --ignore Kommagetrennte Liste von Verzeichnissen, die ignoriert werden sollen
|
||||
--reset Löscht das Logfile 'processed.log' und beendet sich
|
||||
-h, --hilfe Zeigt diese Hilfe
|
||||
|
||||
Beispiel:
|
||||
ts-node link_collector.ts -s docs,notes -x "docs/alt"
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
class FileScanner {
|
||||
static *find(rootDirs: string[], ignoreDirs: string[], extensions: string[]): Generator<string> {
|
||||
for (const root of rootDirs) {
|
||||
const absRoot = path.resolve(root);
|
||||
const stack = [absRoot];
|
||||
|
||||
while (stack.length) {
|
||||
const current = stack.pop()!;
|
||||
const rel = path.relative(ScriptInfo.cwd(), current).replace(/\\/g, '/');
|
||||
if (ignoreDirs.some(ignored => rel.startsWith(ignored))) continue;
|
||||
|
||||
const entries = fs.readdirSync(current, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(current, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
stack.push(fullPath);
|
||||
} else if (extensions.some(ext => entry.name.endsWith(ext))) {
|
||||
yield fullPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TitleExtractor {
|
||||
static extract(filepath: string): string {
|
||||
try {
|
||||
const content = fs.readFileSync(filepath, 'utf8');
|
||||
for (const line of content.split('\n')) {
|
||||
if (line.trim().startsWith('#')) {
|
||||
return line.replace(/^#+/, '').trim();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`⚠ Fehler beim Lesen von ${filepath}: ${e}`);
|
||||
}
|
||||
return path.basename(filepath, path.extname(filepath));
|
||||
}
|
||||
}
|
||||
|
||||
class ProcessedLog {
|
||||
private readonly logPath: string;
|
||||
private entries: Set<string>;
|
||||
|
||||
constructor(filename: string) {
|
||||
this.logPath = path.join(ScriptInfo.dir(), filename);
|
||||
this.entries = new Set<string>();
|
||||
this.load();
|
||||
}
|
||||
|
||||
private load() {
|
||||
if (!fs.existsSync(this.logPath)) return;
|
||||
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, '/')));
|
||||
}
|
||||
|
||||
has(posixPath: string): boolean {
|
||||
return this.entries.has(posixPath);
|
||||
}
|
||||
|
||||
update(newPaths: string[]): void {
|
||||
const content = newPaths.map(p => p.replace(/\\/g, '/')).join('\n') + '\n';
|
||||
fs.appendFileSync(this.logPath, content, 'utf8');
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
if (fs.existsSync(this.logPath)) {
|
||||
fs.unlinkSync(this.logPath);
|
||||
console.log('🧹 Logfile gelöscht:', this.logPath);
|
||||
} else {
|
||||
console.log('ℹ Logfile existierte nicht:', this.logPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MarkdownAppender {
|
||||
static append(outputFile: string, links: string[]): void {
|
||||
const content = links.join('\n') + '\n';
|
||||
fs.appendFileSync(outputFile, content, 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
// Einstiegspunkt
|
||||
function main() {
|
||||
const config = ConfigLoader.load();
|
||||
const args = ArgParser.parse();
|
||||
|
||||
if (args.hilfe) {
|
||||
ArgParser.showHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
const log = new ProcessedLog(config.processed_log || 'processed.log');
|
||||
|
||||
if (args.reset) {
|
||||
log.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
const cwd = ScriptInfo.cwd();
|
||||
const outputFile = path.resolve(cwd, config.output_file || 'output.md');
|
||||
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 extensions = config.extensions || ['.md'];
|
||||
|
||||
const newLinks: string[] = [];
|
||||
const newProcessed: string[] = [];
|
||||
|
||||
for (const absPath of FileScanner.find(rootDirs, ignoreDirs, extensions)) {
|
||||
const relPath = path.relative(cwd, absPath).replace(/\\/g, '/');
|
||||
if (path.resolve(absPath) === outputFile || log.has(relPath)) continue;
|
||||
|
||||
const title = TitleExtractor.extract(absPath);
|
||||
newLinks.push(`- [${title}](${relPath})`);
|
||||
newProcessed.push(relPath);
|
||||
}
|
||||
|
||||
if (newLinks.length > 0) {
|
||||
MarkdownAppender.append(outputFile, newLinks);
|
||||
log.update(newProcessed);
|
||||
console.log(`✔ ${newLinks.length} neue Links hinzugefügt.`);
|
||||
} else {
|
||||
console.log(' ℹ Keine neuen Dateien gefunden.');
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
#!/usr/bin/env node
|
||||
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname } from 'node:path';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
type Config = {
|
||||
root_dirs?: string[];
|
||||
output_file?: string;
|
||||
processed_log?: string;
|
||||
extensions?: string[];
|
||||
};
|
||||
|
||||
type Args = {
|
||||
scan: string[] | null;
|
||||
ignore: string[];
|
||||
reset: boolean;
|
||||
hilfe: boolean;
|
||||
};
|
||||
|
||||
class ScriptInfo {
|
||||
static dir(): string {
|
||||
return path.dirname(__filename);
|
||||
}
|
||||
|
||||
static cwd(): string {
|
||||
return process.cwd();
|
||||
}
|
||||
}
|
||||
|
||||
class ConfigLoader {
|
||||
static load(filename = 'config.jsonc'): Config {
|
||||
const configPath = path.join(ScriptInfo.dir(), filename);
|
||||
if (!fs.existsSync(configPath)) {
|
||||
console.error(` ⚠ Konfigurationsdatei nicht gefunden: ${configPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
const raw = fs.readFileSync(configPath, 'utf8');
|
||||
const clean = raw
|
||||
.split('\n')
|
||||
.filter(line => !line.trim().startsWith('//'))
|
||||
.join('');
|
||||
return JSON.parse(clean);
|
||||
}
|
||||
}
|
||||
|
||||
class ArgParser {
|
||||
static parse(): Args {
|
||||
const argv = process.argv.slice(2);
|
||||
const result: Args = { scan: null, ignore: [], reset: false, hilfe: false };
|
||||
|
||||
while (argv.length) {
|
||||
const arg = argv.shift();
|
||||
if (!arg) break;
|
||||
|
||||
if (arg === '-h' || arg === '--hilfe') {
|
||||
result.hilfe = true;
|
||||
} else if (arg === '--reset') {
|
||||
result.reset = true;
|
||||
} else if ((arg === '-s' || arg === '--scan') && argv.length) {
|
||||
result.scan = argv.shift()!.split(',').map(x => x.trim()).filter(Boolean);
|
||||
} else if ((arg === '-x' || arg === '--ignore') && argv.length) {
|
||||
result.ignore = argv.shift()!.split(',').map(x => x.trim()).filter(Boolean);
|
||||
} else {
|
||||
console.warn(` ⚠ Unbekannter Parameter: ${arg}`);
|
||||
result.hilfe = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static showHelp(): void {
|
||||
console.log(`
|
||||
(C) 2025 - Adam Skotarczak (ionivation.com)
|
||||
|
||||
🛈 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]
|
||||
|
||||
-s, --scan Kommagetrennte Liste von Verzeichnissen zum Durchsuchen (relativ zum Aufrufpfad)
|
||||
-x, --ignore Kommagetrennte Liste von Verzeichnissen, die ignoriert werden sollen
|
||||
--reset Löscht das Logfile 'processed.log' und beendet sich
|
||||
-h, --hilfe Zeigt diese Hilfe
|
||||
|
||||
Beispiel:
|
||||
ts-node link_collector.ts -s docs,notes -x "docs/alt"
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
class FileScanner {
|
||||
static *find(rootDirs: string[], ignoreDirs: string[], extensions: string[]): Generator<string> {
|
||||
for (const root of rootDirs) {
|
||||
const absRoot = path.resolve(root);
|
||||
const stack = [absRoot];
|
||||
|
||||
while (stack.length) {
|
||||
const current = stack.pop()!;
|
||||
const rel = path.relative(ScriptInfo.cwd(), current).replace(/\\/g, '/');
|
||||
if (ignoreDirs.some(ignored => rel.startsWith(ignored))) continue;
|
||||
|
||||
const entries = fs.readdirSync(current, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(current, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
stack.push(fullPath);
|
||||
} else if (extensions.some(ext => entry.name.endsWith(ext))) {
|
||||
yield fullPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TitleExtractor {
|
||||
static extract(filepath: string): string {
|
||||
try {
|
||||
const content = fs.readFileSync(filepath, 'utf8');
|
||||
for (const line of content.split('\n')) {
|
||||
if (line.trim().startsWith('#')) {
|
||||
return line.replace(/^#+/, '').trim();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`⚠ Fehler beim Lesen von ${filepath}: ${e}`);
|
||||
}
|
||||
return path.basename(filepath, path.extname(filepath));
|
||||
}
|
||||
}
|
||||
|
||||
class ProcessedLog {
|
||||
private readonly logPath: string;
|
||||
private entries: Set<string>;
|
||||
|
||||
constructor(filename: string) {
|
||||
this.logPath = path.join(ScriptInfo.dir(), filename);
|
||||
this.entries = new Set<string>();
|
||||
this.load();
|
||||
}
|
||||
|
||||
private load() {
|
||||
if (!fs.existsSync(this.logPath)) return;
|
||||
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, '/')));
|
||||
}
|
||||
|
||||
has(posixPath: string): boolean {
|
||||
return this.entries.has(posixPath);
|
||||
}
|
||||
|
||||
update(newPaths: string[]): void {
|
||||
const content = newPaths.map(p => p.replace(/\\/g, '/')).join('\n') + '\n';
|
||||
fs.appendFileSync(this.logPath, content, 'utf8');
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
if (fs.existsSync(this.logPath)) {
|
||||
fs.unlinkSync(this.logPath);
|
||||
console.log('🧹 Logfile gelöscht:', this.logPath);
|
||||
} else {
|
||||
console.log('ℹ Logfile existierte nicht:', this.logPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MarkdownAppender {
|
||||
static append(outputFile: string, links: string[]): void {
|
||||
const content = links.join('\n') + '\n';
|
||||
fs.appendFileSync(outputFile, content, 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
// Einstiegspunkt
|
||||
function main() {
|
||||
const config = ConfigLoader.load();
|
||||
const args = ArgParser.parse();
|
||||
|
||||
if (args.hilfe) {
|
||||
ArgParser.showHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
const log = new ProcessedLog(config.processed_log || 'processed.log');
|
||||
|
||||
if (args.reset) {
|
||||
log.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
const cwd = ScriptInfo.cwd();
|
||||
const outputFile = path.resolve(cwd, config.output_file || 'output.md');
|
||||
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 extensions = config.extensions || ['.md'];
|
||||
|
||||
const newLinks: string[] = [];
|
||||
const newProcessed: string[] = [];
|
||||
|
||||
for (const absPath of FileScanner.find(rootDirs, ignoreDirs, extensions)) {
|
||||
const relPath = path.relative(cwd, absPath).replace(/\\/g, '/');
|
||||
if (path.resolve(absPath) === outputFile || log.has(relPath)) continue;
|
||||
|
||||
const title = TitleExtractor.extract(absPath);
|
||||
newLinks.push(`- [${title}](${relPath})`);
|
||||
newProcessed.push(relPath);
|
||||
}
|
||||
|
||||
if (newLinks.length > 0) {
|
||||
MarkdownAppender.append(outputFile, newLinks);
|
||||
log.update(newProcessed);
|
||||
console.log(`✔ ${newLinks.length} neue Links hinzugefügt.`);
|
||||
} else {
|
||||
console.log(' ℹ Keine neuen Dateien gefunden.');
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
|
@ -1,80 +1,80 @@
|
||||
#!/usr/bin/env ts-node
|
||||
|
||||
/**
|
||||
* Robust plattformunabhängiger Dateikopierer
|
||||
* Verwendung: node fscopy.ts -s <quelle> -t <ziel>
|
||||
* Optionen: -h | --help
|
||||
*/
|
||||
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
function showHelp(): void {
|
||||
console.log(`
|
||||
Copy Files with node.js
|
||||
Verwendung:
|
||||
node fscopy.ts -s <quelle> -q <ziel>
|
||||
|
||||
Parameter:
|
||||
-s, --source Pfad zur Quelldatei (z.B. static/.htaccess)
|
||||
-t, --target Pfad zur Zieldatei (z.B. dist/app/.htaccess)
|
||||
-h, --help Diese Hilfe anzeigen
|
||||
`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
function parseArgs(): { source: string; ziel: string } {
|
||||
const args = process.argv.slice(2);
|
||||
let source = "";
|
||||
let ziel = "";
|
||||
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
switch (args[i]) {
|
||||
case "-s":
|
||||
case "--source":
|
||||
source = args[++i];
|
||||
break;
|
||||
case "-t":
|
||||
case "--target":
|
||||
ziel = args[++i];
|
||||
break;
|
||||
case "-h":
|
||||
case "--help":
|
||||
showHelp();
|
||||
break;
|
||||
default:
|
||||
console.error(`Unbekannter Parameter: ${args[i]}`);
|
||||
showHelp();
|
||||
}
|
||||
}
|
||||
|
||||
if (!source || !ziel) {
|
||||
console.error("❌ Quelle und Ziel müssen angegeben werden.");
|
||||
showHelp();
|
||||
}
|
||||
|
||||
return { source, ziel };
|
||||
}
|
||||
|
||||
function copyFile(source: string, ziel: string): void {
|
||||
const zielVerzeichnis = path.dirname(ziel);
|
||||
fs.mkdir(zielVerzeichnis, { recursive: true }, (mkdirErr) => {
|
||||
if (mkdirErr) {
|
||||
console.error(`❌ Zielverzeichnis konnte nicht erstellt werden: ${mkdirErr.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
fs.copyFile(source, ziel, (copyErr) => {
|
||||
if (copyErr) {
|
||||
console.error(`❌ Fehler beim Kopieren: ${copyErr.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`✔ Datei erfolgreich kopiert: ${source} → ${ziel}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Ausführung
|
||||
const { source, ziel } = parseArgs();
|
||||
copyFile(source, ziel);
|
||||
#!/usr/bin/env ts-node
|
||||
|
||||
/**
|
||||
* Robust plattformunabhängiger Dateikopierer
|
||||
* Verwendung: node fscopy.ts -s <quelle> -t <ziel>
|
||||
* Optionen: -h | --help
|
||||
*/
|
||||
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
function showHelp(): void {
|
||||
console.log(`
|
||||
Copy Files with node.js
|
||||
Verwendung:
|
||||
node fscopy.ts -s <quelle> -q <ziel>
|
||||
|
||||
Parameter:
|
||||
-s, --source Pfad zur Quelldatei (z.B. static/.htaccess)
|
||||
-t, --target Pfad zur Zieldatei (z.B. dist/app/.htaccess)
|
||||
-h, --help Diese Hilfe anzeigen
|
||||
`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
function parseArgs(): { source: string; ziel: string } {
|
||||
const args = process.argv.slice(2);
|
||||
let source = "";
|
||||
let ziel = "";
|
||||
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
switch (args[i]) {
|
||||
case "-s":
|
||||
case "--source":
|
||||
source = args[++i];
|
||||
break;
|
||||
case "-t":
|
||||
case "--target":
|
||||
ziel = args[++i];
|
||||
break;
|
||||
case "-h":
|
||||
case "--help":
|
||||
showHelp();
|
||||
break;
|
||||
default:
|
||||
console.error(`Unbekannter Parameter: ${args[i]}`);
|
||||
showHelp();
|
||||
}
|
||||
}
|
||||
|
||||
if (!source || !ziel) {
|
||||
console.error("❌ Quelle und Ziel müssen angegeben werden.");
|
||||
showHelp();
|
||||
}
|
||||
|
||||
return { source, ziel };
|
||||
}
|
||||
|
||||
function copyFile(source: string, ziel: string): void {
|
||||
const zielVerzeichnis = path.dirname(ziel);
|
||||
fs.mkdir(zielVerzeichnis, { recursive: true }, (mkdirErr) => {
|
||||
if (mkdirErr) {
|
||||
console.error(`❌ Zielverzeichnis konnte nicht erstellt werden: ${mkdirErr.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
fs.copyFile(source, ziel, (copyErr) => {
|
||||
if (copyErr) {
|
||||
console.error(`❌ Fehler beim Kopieren: ${copyErr.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`✔ Datei erfolgreich kopiert: ${source} → ${ziel}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Ausführung
|
||||
const { source, ziel } = parseArgs();
|
||||
copyFile(source, ziel);
|
||||
|
@ -1,41 +1,41 @@
|
||||
#!/usr/bin/env ts-node
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
/**
|
||||
* Löscht eine Datei am angegebenen Pfad.
|
||||
*
|
||||
* @param filePath - Pfad zur Datei, die gelöscht werden soll
|
||||
*/
|
||||
function deleteFile(filePath: string): void {
|
||||
const resolvedPath = path.resolve(filePath);
|
||||
|
||||
if (!fs.existsSync(resolvedPath)) {
|
||||
console.error(`❌ Datei nicht gefunden: ${resolvedPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
fs.unlinkSync(resolvedPath);
|
||||
console.log(`✔ Datei gelöscht: ${resolvedPath}`);
|
||||
} catch (err) {
|
||||
console.error(`❌ Fehler beim Löschen: ${(err as Error).message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Kommandozeilenargumente
|
||||
const [, , arg] = process.argv;
|
||||
|
||||
if (!arg || arg === '-h' || arg === '--help') {
|
||||
console.log(`Verwendung:
|
||||
ts-node delete.ts <dateipfad>
|
||||
|
||||
Beispiel:
|
||||
ts-node delete.ts ./log/output.txt`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Datei löschen
|
||||
deleteFile(arg);
|
||||
#!/usr/bin/env ts-node
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
/**
|
||||
* Löscht eine Datei am angegebenen Pfad.
|
||||
*
|
||||
* @param filePath - Pfad zur Datei, die gelöscht werden soll
|
||||
*/
|
||||
function deleteFile(filePath: string): void {
|
||||
const resolvedPath = path.resolve(filePath);
|
||||
|
||||
if (!fs.existsSync(resolvedPath)) {
|
||||
console.error(`❌ Datei nicht gefunden: ${resolvedPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
fs.unlinkSync(resolvedPath);
|
||||
console.log(`✔ Datei gelöscht: ${resolvedPath}`);
|
||||
} catch (err) {
|
||||
console.error(`❌ Fehler beim Löschen: ${(err as Error).message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Kommandozeilenargumente
|
||||
const [, , arg] = process.argv;
|
||||
|
||||
if (!arg || arg === '-h' || arg === '--help') {
|
||||
console.log(`Verwendung:
|
||||
ts-node delete.ts <dateipfad>
|
||||
|
||||
Beispiel:
|
||||
ts-node delete.ts ./log/output.txt`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Datei löschen
|
||||
deleteFile(arg);
|
||||
|
@ -1,11 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "./tools/dist",
|
||||
"rootDir": "./tools/src",
|
||||
"strict": true
|
||||
},
|
||||
"include": ["tools/src"]
|
||||
}
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "./tools/dist",
|
||||
"rootDir": "./tools/src",
|
||||
"strict": true
|
||||
},
|
||||
"include": ["tools/src"]
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user