Compare commits

..

53 Commits

Author SHA1 Message Date
a-kenji
3a73b4cb74 WIP: try to improve nixd completion 2024-05-29 09:27:52 +02:00
a-kenji
968749ee63 add: options.nix 2024-05-28 20:10:05 +02:00
clan-bot
b9788a5dba Merge pull request 'clan/docs.py: remove epilog from the reference overview' (#1487) from a-kenji-cli/docs/reference-overview into main 2024-05-28 18:05:07 +00:00
a-kenji
7078f09872 clan/docs.py: remove epilog from the reference overview 2024-05-28 20:01:48 +02:00
Mic92
1aa7808c02 Merge pull request 'Update Contributing guide to external developers' (#1484) from Qubasa/clan-core:main into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/1484
2024-05-28 16:12:11 +00:00
Qubasa
ba8a51101d Update Contributing guide to external developers 2024-05-28 18:06:31 +02:00
clan-bot
de69c970aa Merge pull request 'packaging: package clan gui for many distros' (#1485) from DavHau-dave into main 2024-05-28 15:54:08 +00:00
DavHau
fe5fa6a85d packaging: package clan gui for many distros 2024-05-28 17:50:32 +02:00
clan-bot
de74febf64 Merge pull request 'packaging: package clan gui for many distros' (#1483) from DavHau-dave into main 2024-05-28 15:37:18 +00:00
DavHau
3b6483e819 packaging: package clan gui for many distros 2024-05-28 17:33:55 +02:00
clan-bot
dcd6ad0983 Merge pull request 'Docs: fix relative links to git.clan.lol' (#1482) from hsjobeki-main into main 2024-05-28 15:18:45 +00:00
Johannes Kirschbauer
567d979243 Docs: fix relative links to git.clan.lol 2024-05-28 17:14:16 +02:00
clan-bot
c81a8681b0 Merge pull request 'clan/docs.py: add epilog to reference docs' (#1481) from a-kenji-docs/epilog into main 2024-05-28 15:13:57 +00:00
a-kenji
31cde90819 clan/docs.py: add epilog to reference docs
Fixes #1469
2024-05-28 17:08:46 +02:00
clan-bot
a77bf5bf21 Merge pull request 'Docs: use offline fonts' (#1480) from hsjobeki-main into main 2024-05-28 15:05:22 +00:00
Johannes Kirschbauer
4befa80eb8 Docs: use offline fonts 2024-05-28 16:58:59 +02:00
clan-bot
52584662a8 Merge pull request 'Fix typos' (#1477) from a-kenji-fix/typos into main 2024-05-28 13:02:19 +00:00
a-kenji
de147f63e9 Fix typos 2024-05-28 14:58:38 +02:00
clan-bot
96c33dec7a Merge pull request 'consistent rename cLAN -> Clan' (#1475) from rename into main 2024-05-28 11:38:57 +00:00
Jörg Thalheim
3c0b5f0867 drop deprecated mdDoc 2024-05-28 13:35:11 +02:00
clan-bot
c252f11c1f Merge pull request 'docs/secrets: improve chapter assigning access' (#1474) from DavHau-dave into main 2024-05-28 11:11:46 +00:00
DavHau
f1f040397d docs/secrets: improve chapter assigning access
Since we already walk the user through creating a secret in an earlier step, it makes more sense explain first how to add machines/users to an existing secret instead of creating  a new one
2024-05-28 13:08:19 +02:00
clan-bot
418e9937cb Merge pull request 'clan: add descriptions for reference documentation' (#1473) from a-kenji-cli/doc into main 2024-05-28 09:40:50 +00:00
a-kenji
c34664429c clan: add descriptions for reference documentation 2024-05-28 11:37:32 +02:00
clan-bot
6fe5928297 Merge pull request 'clan: add run_no_stdout function suppressing stdout' (#1472) from a-kenji-run_no_stdout into main 2024-05-28 09:17:14 +00:00
a-kenji
eee99730d1 clan: add run_no_stdout function suppressing stdout
Add the `run_no_stdout` function suppressing stdout by default.This
keeps the noise down on most commands, while still
stayingdebuggable.Stdout will be active when the `--debug` flag is
passed to the cli.

Fixes #1443
2024-05-28 11:13:55 +02:00
clan-bot
9394760e3b Merge pull request 'editor: improve nixpkgs option completions' (#1470) from a-kenji-improve/editor into main 2024-05-28 07:38:09 +00:00
a-kenji
a0b0e1a0ac editor: improve nixpkgs option completions 2024-05-28 09:34:57 +02:00
clan-bot
dbaa26ccaa Merge pull request 'clan: machines --help add examples to help output' (#1468) from a-kenji-clan/cli/machines-examples into main 2024-05-27 19:04:30 +00:00
a-kenji
d1591d4485 clan: machines --help add examples to help output 2024-05-27 21:01:05 +02:00
clan-bot
c68a8306ba Merge pull request 'clan: duplicate description field for generation of the reference documentation' (#1467) from a-kenji-clan/cli/add-description into main 2024-05-27 18:32:54 +00:00
a-kenji
ec9f605004 clan: duplicate description field for generation of the reference documentation 2024-05-27 20:29:34 +02:00
clan-bot
e60efea1f7 Merge pull request 'clan: ssh --help add examples' (#1466) from a-kenji-clan/help/ssh into main 2024-05-27 18:18:08 +00:00
a-kenji
efacb7f184 clan: ssh --help add examples
Add examples to the output of `clan ssh --help`.
2024-05-27 20:14:37 +02:00
clan-bot
67275aac63 Merge pull request 'clan: rename cLan to clan' (#1465) from a-kenji-rename-clan into main 2024-05-27 17:56:32 +00:00
a-kenji
a704a05b15 clan: rename cLan to clan 2024-05-27 19:52:51 +02:00
Mic92
01aafc520d Merge pull request 'consistent rename cLAN -> Clan' (#1464) from rename into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/1464
2024-05-27 13:58:32 +00:00
Jörg Thalheim
c0a54f539a consistent rename cLAN -> Clan 2024-05-27 13:58:32 +00:00
Jörg Thalheim
e2d7e6e86c consistent rename cLAN -> Clan 2024-05-27 15:54:17 +02:00
clan-bot
1df4e361f7 Merge pull request 'clan: add examples and description to most help' (#1463) from a-kenji-clan/examples into main 2024-05-27 12:37:22 +00:00
a-kenji
e8bd5ad24b clan: add examples and description to most help
Add examples and description to most toplevel help outputs.
2024-05-27 14:33:58 +02:00
clan-bot
775f993ecc Merge pull request 'clan-cli: Fix nix develop not working in template because of symlink' (#1462) from Qubasa-main into main 2024-05-27 12:05:17 +00:00
Qubasa
0e1478edcd clan-cli: Fix nix develop not working in template because of symlink 2024-05-27 14:00:31 +02:00
clan-bot
bfc1203a8a Merge pull request 'init: vscode .#editor' (#1461) from Qubasa-init/editors into main 2024-05-27 12:00:26 +00:00
Qubasa
2bd8b144b9 init: vscode .#editor 2024-05-27 13:52:54 +02:00
clan-bot
b52b2221b0 Merge pull request 'drop offline in nix shell' (#1459) from fix-mass-rebuilds into main 2024-05-27 11:43:32 +00:00
Jörg Thalheim
64adf17368 drop offline in nix shell
Otherwise we become gentoo!
2024-05-27 13:40:11 +02:00
clan-bot
509d8c1dae Merge pull request 'make git-hooks opt-in' (#1453) from git-hooks into main 2024-05-27 10:34:07 +00:00
clan-bot
295de17640 Merge pull request 'docs: secrets: list the main steps of the guide' (#1456) from DavHau-dave into main 2024-05-27 10:05:55 +00:00
DavHau
b158c2706f docs: secrets: list the main steps of the guide
... so the user has a routh idea about the mein steps
2024-05-27 12:02:29 +02:00
clan-bot
750979c988 Merge pull request 'A Kenji Clan/Cli/Fix Naming' (#1455) from a-kenji-clan/cli/fix-naming into main 2024-05-27 09:54:36 +00:00
a-kenji
6d7849a03c clan: fix description of cli tool 2024-05-27 11:51:25 +02:00
Jörg Thalheim
f46fd3ace6 make git-hooks opt-in
pre-commit hook break git commits and are disruptive.
Therefore people that want to enable this feature, should enable it locally instead.
I.e. treefmt will also check untracked files that are not meant for the current commit.
2024-05-27 11:08:17 +02:00
39 changed files with 533 additions and 158 deletions

View File

@@ -1,4 +1,4 @@
# Contributing to cLAN
# Contributing to Clan
## Live-reloading documentation

View File

@@ -1,6 +1,6 @@
# Clan Core Repository
Welcome to the Clan Core Repository, the heart of the [clan.lol](https://clan.lol/) project! This monorepo is the foundation of Clan, a revolutionary open-source project aimed at restoring fun, freedom, and functionality to computing. Here, you'll find all the essential packages, NixOS modules, CLI tools, and tests needed to contribute to and work with the cLAN project. Clan leverages the Nix system to ensure reliability, security, and seamless management of digital environments, putting the power back into the hands of users.
Welcome to the Clan Core Repository, the heart of the [clan.lol](https://clan.lol/) project! This monorepo is the foundation of Clan, a revolutionary open-source project aimed at restoring fun, freedom, and functionality to computing. Here, you'll find all the essential packages, NixOS modules, CLI tools, and tests needed to contribute to and work with the Clan project. Clan leverages the Nix system to ensure reliability, security, and seamless management of digital environments, putting the power back into the hands of users.
## Why Clan?

View File

@@ -9,7 +9,7 @@
# - cli frontend: https://github.com/localsend/localsend/issues/11
# - ipv6 support: https://github.com/localsend/localsend/issues/549
options.clan.localsend = {
enable = lib.mkEnableOption (lib.mdDoc "enable the localsend module");
enable = lib.mkEnableOption "enable the localsend module";
defaultLocation = lib.mkOption {
type = lib.types.str;
description = "The default download location";

View File

@@ -1,4 +1,4 @@
{ inputs, ... }:
{ ... }:
{
perSystem =
{
@@ -9,7 +9,6 @@
}:
let
writers = pkgs.callPackage ./pkgs/builders/script-writers.nix { };
inherit (pkgs.callPackage inputs.git-hooks { }) lib;
ansiEscapes = {
reset = ''\033[0m'';
@@ -22,11 +21,6 @@
select-shell = writers.writePython3Bin "select-shell" {
flakeIgnore = [ "E501" ];
} ./pkgs/scripts/select-shell.py;
# run treefmt before each commit
install-pre-commit-hook =
with lib.git-hooks;
pre-commit (wrap.abort-on-change config.treefmt.build.wrapper);
in
{
devShells.default = pkgs.mkShell {
@@ -41,8 +35,6 @@
config.treefmt.build.wrapper
];
shellHook = ''
${install-pre-commit-hook}
echo -e "${ansiEscapes.green}switch to another dev-shell using: select-shell${ansiEscapes.reset}"
'';
};

4
docs/.gitignore vendored
View File

@@ -1 +1,3 @@
/site/reference
/site/reference
/site/static/Roboto-Regular.ttf
/site/static/FiraCode-VF.ttf

View File

@@ -22,9 +22,9 @@ Let's get your development environment up and running:
2. **Install direnv**:
- Download the direnv package from [here](https://direnv.net/docs/installation.html) or run the following command:
- To automatically setup a devshell on entering the directory
```bash
curl -sfL https://direnv.net/install.sh | bash
nix profile install nixpkgs#nix-direnv-flakes
```
3. **Add direnv to your shell**:
@@ -36,9 +36,14 @@ Let's get your development environment up and running:
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc && echo 'eval "$(direnv hook bash)"' >> ~/.bashrc && eval "$SHELL"
```
4. **Clone the Repository and Navigate**:
- Clone this repository and navigate to it.
4. **Create a Gitea Account**:
- Register an account on https://git.clan.lol
- Fork the [clan-core](https://git.clan.lol/clan/clan-core) repository
- Clone the repository and navigate to it
- Add a new remote called upstream:
```bash
git remote add upstream gitea@git.clan.lol:clan/clan-core.git
```
5. **Allow .envrc**:
@@ -48,59 +53,68 @@ Let's get your development environment up and running:
```
- Execute `direnv allow` to automatically execute the shell script `.envrc` when entering the directory.
# Setting Up Your Git Workflow
Let's set up your Git workflow to collaborate effectively:
1. **Register Your Gitea Account Locally**:
- Execute the following command to add your Gitea account locally:
```bash
tea login add
```
- Fill out the prompt as follows:
- URL of Gitea instance: `https://git.clan.lol`
- Name of new Login [gitea.gchq.icu]: `gitea.gchq.icu:7171`
- Do you have an access token? No
- Username: YourUsername
- Password: YourPassword
- Set Optional settings: No
2. **Git Workflow**:
1. Add your changes to Git using `git add <file1> <file2>`.
2. Run `nix fmt` to lint your files.
3. Commit your changes with a descriptive message: `git commit -a -m "My descriptive commit message"`.
4. Make sure your branch has the latest changes from upstream by executing:
6. **(Optional) Install Git Hooks**:
- To syntax check your code you can run:
```bash
git fetch && git rebase origin/main --autostash
nix fmt
```
- To make this automatic install the git hooks
```bash
./scripts/pre-commit
```
5. Use `git status` to check for merge conflicts.
6. If conflicts exist, resolve them. Here's a tutorial for resolving conflicts in [VSCode](https://code.visualstudio.com/docs/sourcecontrol/overview#_merge-conflicts).
7. After resolving conflicts, execute `git merge --continue` and repeat step 5 until there are no conflicts.
3. **Create a Pull Request**:
- To automatically open a pull request that gets merged if all tests pass, execute:
```bash
merge-after-ci
```
4. **Review Your Pull Request**:
- Visit https://git.clan.lol and go to the project page. Check under "Pull Requests" for any issues with your pull request.
5. **Push Your Changes**:
- If there are issues, fix them and redo step 2. Afterward, execute:
```bash
git push origin HEAD:YourUsername-main
```
- This will directly push to your open pull request.
7. **Open a Pull Request**:
- Go to the webinterface and open up a pull request
# Debugging
Here are some methods for debugging and testing the clan-cli:
## See all possible packages and tests
To quickly show all possible packages and tests execute:
```bash
nix flake show --system no-eval
```
Under `checks` you will find all tests that are executed in our CI. Under `packages` you find all our projects.
```
git+file:///home/lhebendanz/Projects/clan-core
├───apps
│ └───x86_64-linux
│ ├───install-vm: app
│ └───install-vm-nogui: app
├───checks
│ └───x86_64-linux
│ ├───borgbackup omitted (use '--all-systems' to show)
│ ├───check-for-breakpoints omitted (use '--all-systems' to show)
│ ├───clan-dep-age omitted (use '--all-systems' to show)
│ ├───clan-dep-bash omitted (use '--all-systems' to show)
│ ├───clan-dep-e2fsprogs omitted (use '--all-systems' to show)
│ ├───clan-dep-fakeroot omitted (use '--all-systems' to show)
│ ├───clan-dep-git omitted (use '--all-systems' to show)
│ ├───clan-dep-nix omitted (use '--all-systems' to show)
│ ├───clan-dep-openssh omitted (use '--all-systems' to show)
│ ├───"clan-dep-python3.11-mypy" omitted (use '--all-systems' to show)
├───packages
│ └───x86_64-linux
│ ├───clan-cli omitted (use '--all-systems' to show)
│ ├───clan-cli-docs omitted (use '--all-systems' to show)
│ ├───clan-ts-api omitted (use '--all-systems' to show)
│ ├───clan-vm-manager omitted (use '--all-systems' to show)
│ ├───default omitted (use '--all-systems' to show)
│ ├───deploy-docs omitted (use '--all-systems' to show)
│ ├───docs omitted (use '--all-systems' to show)
│ ├───editor omitted (use '--all-systems' to show)
└───templates
├───default: template: Initialize a new clan flake
└───new-clan: template: Initialize a new clan flake
```
You can execute every test separately by following the tree path `nix build .#checks.x86_64-linux.clan-pytest` for example.
## Test Locally in Devshell with Breakpoints
To test the cli locally in a development environment and set breakpoints for debugging, follow these steps:
@@ -150,12 +164,14 @@ If you need to inspect the Nix sandbox while running tests, follow these steps:
2. Use `cntr` and `psgrep` to attach to the Nix sandbox. This allows you to interactively debug your code while it's paused. For example:
```bash
cntr exec -w your_sandbox_name
psgrep -a -x your_python_process_name
cntr attach <container id, container name or process id>
```
Or you can also use the [nix breakpoint hook](https://nixos.org/manual/nixpkgs/stable/#breakpointhook)
# Standards
Every new module name should be in kebab-case.
Every fact definition, where possible should be in kebab-case.
- Every new module name should be in kebab-case.
- Every fact definition, where possible should be in kebab-case.

View File

@@ -20,11 +20,11 @@ There are several reasons for choosing to self-host. These can include:
Alice wants to self-host a mumble server for her family.
- She visits to the cLAN website, and follows the instructions on how to install cLAN-OS on her server.
- Alice logs into a terminal on her server via SSH (alternatively uses cLAN GUI app)
- Using the cLAN CLI or GUI tool, alice creates a new private network for her family (VPN)
- Alice now browses a list of curated cLAN modules and finds a module for mumble.
- She adds this module to her network using the cLAN tool.
- She visits to the Clan website, and follows the instructions on how to install Clan-OS on her server.
- Alice logs into a terminal on her server via SSH (alternatively uses Clan GUI app)
- Using the Clan CLI or GUI tool, alice creates a new private network for her family (VPN)
- Alice now browses a list of curated Clan modules and finds a module for mumble.
- She adds this module to her network using the Clan tool.
- After that, she uses the clan tool to invite her family members to her network
- Other family members join the private network via the invitation.
- By accepting the invitation, other members automatically install all required software to interact with the network on their machine.
@@ -33,7 +33,7 @@ Alice wants to self-host a mumble server for her family.
Alice wants to add a photos app to her private network
- She uses the clan CLI or GUI tool to manage her existing private cLAN family network
- She uses the clan CLI or GUI tool to manage her existing private Clan family network
- She discovers a module for photoprism, and adds it to her server using the tool
- Other members who are already part of her network, will receive a notification that an update is required to their environment
- After accepting, all new software and services to interact with the new photoprism service will be installed automatically.

View File

@@ -1,4 +1,4 @@
# Joining a cLAN network
# Joining a Clan network
## General Description
@@ -8,13 +8,13 @@ Joining a self-hosted infrastructure involves connecting to a network, server, o
### Story 1: Joining a private network
Alice' son Bob has never heard of cLAN, but receives an invitation URL from Alice who already set up private cLAN network for her family.
Alice' son Bob has never heard of Clan, but receives an invitation URL from Alice who already set up private Clan network for her family.
Bob opens the invitation link and lands on the cLAN website. He quickly learns about what cLAN is and can see that the invitation is for a private network of his family that hosts a number of services, like a private voice chat and a photo sharing platform.
Bob opens the invitation link and lands on the Clan website. He quickly learns about what Clan is and can see that the invitation is for a private network of his family that hosts a number of services, like a private voice chat and a photo sharing platform.
Bob decides to join the network and follows the instructions to install the cLAN tool on his computer.
Bob decides to join the network and follows the instructions to install the Clan tool on his computer.
Feeding the invitation link to the cLAN tool, bob registers his machine with the network.
Feeding the invitation link to the Clan tool, bob registers his machine with the network.
All programs required to interact with the network will be installed and configured automatically and securely.
@@ -22,7 +22,7 @@ Optionally, bob can customize the configuration of these programs through a simp
### Story 2: Receiving breaking changes
The cLAN family network which Bob is part of received an update.
The Clan family network which Bob is part of received an update.
The existing photo sharing service has been removed and replaced with another alternative service. The new photo sharing service requires a different client app to view and upload photos.
@@ -30,7 +30,7 @@ Bob accepts the update. Now his environment will be updated. The old client soft
Because Bob has customized the previous photo viewing app, he is notified that this customization is no longer valid, as the software has been removed (deprecation message).l
Optionally, Bob can now customize the new photo viewing software through his cLAN configuration app or via a config file.
Optionally, Bob can now customize the new photo viewing software through his Clan configuration app or via a config file.
## Challenges

View File

@@ -1,10 +1,10 @@
# cLAN module maintaining
# Clan module maintaining
## General Description
cLAN modules are pieces of software that can be used by admins to build a private or public infrastructure.
Clan modules are pieces of software that can be used by admins to build a private or public infrastructure.
cLAN modules should have the following properties:
Clan modules should have the following properties:
1. Documented: It should be clear what the module does and how to use it.
1. Self contained: A module should be usable as is. If it requires any other software or settings, those should be delivered with the module itself.

View File

@@ -39,7 +39,7 @@ exclude_docs: |
nav:
- Blog:
- blog/index.md
- blog/index.md
- Getting started:
- index.md
- Installer: getting-started/installer.md
@@ -94,6 +94,7 @@ docs_dir: site
site_dir: out
theme:
font: false
logo: https://clan.lol/static/logo/clan-white.png
favicon: https://clan.lol/static/logo/clan-dark.png
name: material
@@ -105,8 +106,6 @@ theme:
- content.tabs.link
icon:
repo: fontawesome/brands/git
font:
code: Roboto Mono
palette:
# Palette toggle for light mode
@@ -128,6 +127,7 @@ theme:
name: Switch to light mode
extra_css:
- static/extra.css
- static/asciinema-player/custom-theme.css
- static/asciinema-player/asciinema-player.css
@@ -142,7 +142,6 @@ extra:
- icon: fontawesome/solid/rss
link: /feed_rss_created.xml
plugins:
- search
- blog

View File

@@ -4,6 +4,8 @@
clan-cli-docs,
asciinema-player-js,
asciinema-player-css,
roboto,
fira-code,
...
}:
let
@@ -33,6 +35,10 @@ pkgs.stdenv.mkDerivation {
mkdir -p ./site/static/asciinema-player
ln -snf ${asciinema-player-js} ./site/static/asciinema-player/asciinema-player.min.js
ln -snf ${asciinema-player-css} ./site/static/asciinema-player/asciinema-player.css
# Link to fonts
ln -snf ${roboto}/share/fonts/truetype/Roboto-Regular.ttf ./site/static/
ln -snf ${fira-code}/share/fonts/truetype/FiraCode-VF.ttf ./site/static/
'';
buildPhase = ''

View File

@@ -40,13 +40,14 @@ def sanitize(text: str) -> str:
return text.replace(">", "\\>")
def replace_store_path(text: str) -> Path:
def replace_store_path(text: str) -> tuple[str, str]:
res = text
if text.startswith("/nix/store/"):
res = "https://git.clan.lol/clan/clan-core/src/branch/main/" + str(
Path(*Path(text).parts[4:])
)
return Path(res)
name = Path(res).name
return (res, name)
def render_option_header(name: str) -> str:
@@ -108,9 +109,10 @@ def render_option(name: str, option: dict[str, Any], level: int = 3) -> str:
"""
decls = option.get("declarations", [])
source_path = replace_store_path(decls[0])
source_path, name = replace_store_path(decls[0])
print(source_path, name)
res += f"""
:simple-git: [{source_path.name}]({source_path})
:simple-git: [{name}]({source_path})
"""
res += "\n"
@@ -160,7 +162,7 @@ def produce_clan_core_docs() -> None:
for option_name, info in options.items():
outfile = f"{module_name}/index.md"
# Create seperate files for nested options
# Create separate files for nested options
if len(option_name.split(".")) <= 2:
# i.e. clan-core.clanDir
output = core_outputs.get(

View File

@@ -5,6 +5,8 @@
clan-cli-docs,
asciinema-player-js,
asciinema-player-css,
roboto,
fira-code,
...
}:
pkgs.mkShell {
@@ -18,7 +20,12 @@ pkgs.mkShell {
echo "Generated API documentation in './site/reference/' "
mkdir -p ./site/static/asciinema-player
ln -snf ${asciinema-player-js} ./site/static/asciinema-player/asciinema-player.min.js
ln -snf ${asciinema-player-css} ./site/static/asciinema-player/asciinema-player.css
# Link to fonts
ln -snf ${roboto}/share/fonts/truetype/Roboto-Regular.ttf ./site/static/
ln -snf ${fira-code}/share/fonts/truetype/FiraCode-VF.ttf ./site/static/
'';
}

View File

@@ -4,10 +4,15 @@ Clan enables encryption of secrets (such as passwords & keys) ensuring security
Clan utilizes the [sops](https://github.com/getsops/sops) format and integrates with [sops-nix](https://github.com/Mic92/sops-nix) on NixOS machines.
This guide will walk you through:
### Create Your Master Keypair
- **Creating a Keypair for Your User**: Learn how to generate a keypair for $USER to securely control all secrets.
- **Creating Your First Secret**: Step-by-step instructions on creating your initial secret.
- **Assigning Machine Access to the Secret**: Understand how to grant a machine access to the newly created secret.
To get started, you'll need to create **Your master keypair**.
## Create Your Admin Keypair
To get started, you'll need to create **Your admin keypair**.
!!! info
Don't worry — if you've already made one before, this step won't change or overwrite it.
@@ -27,7 +32,7 @@ Also add your age public key to the repository with 'clan secrets users add YOUR
!!! warning
Make sure to keep a safe backup of the private key you've just created.
If it's lost, you won't be able to get to your secrets anymore because they all need the master key to be unlocked.
If it's lost, you won't be able to get to your secrets anymore because they all need the admin key to be unlocked.
!!! note
It's safe to add any secrets created by the clan CLI and placed in your repository to version control systems like `git`.
@@ -35,7 +40,7 @@ Also add your age public key to the repository with 'clan secrets users add YOUR
### Add Your Public Key
```bash
clan secrets users add <your_username> <your_public_key>
clan secrets users add $USER <your_public_key>
```
It's best to choose the same username as on your Setup/Admin Machine that you use to control the deployment with.
@@ -101,17 +106,20 @@ In your nixos configuration you can get a path to secrets like this `config.sops
### Assigning Access
By default, secrets are encrypted for your key. To specify which users and machines can access a secret:
When using `clan secrets set <secret>` without arguments, secrets are encrypted for the key of the user named like your current $USER.
```bash
clan secrets set --machine <machine1> --machine <machine2> --user <user1> --user <user2> <secret_name>
```
You can also just add machines/users to existing secrets:
To add machines/users to an existing secret use:
```bash
clan secrets machines add-secret <machine_name> <secret_name>
```
Alternatively specify users and machines while creating a secret:
```bash
clan secrets set --machine <machine1> --machine <machine2> --user <user1> --user <user2> <secret_name>
```
## Advanced
In this section we go into more advanced secret management topics.
@@ -183,11 +191,9 @@ Since our clan secret module will auto-import secrets that are encrypted for a p
you can now remove `sops.secrets.<secrets> = { };` unless you need to specify more options for the secret like owner/group of the secret file.
## Indepth Explanation
The secrets system conceptually knows two different entities:
- **Machine**: consumes secrets

View File

@@ -0,0 +1,13 @@
@font-face {
font-family: "Roboto";
src: url(./Roboto-Regular.ttf) format('truetype');
}
@font-face {
font-family: "Fira Code";
src: url(./FiraCode-VF.ttf) format('truetype');
}
:root {
--md-text-font: "Roboto";
--md-code-font: "Fira Code";
}

17
flake.lock generated
View File

@@ -40,22 +40,6 @@
"type": "github"
}
},
"git-hooks": {
"flake": false,
"locked": {
"lastModified": 1716413087,
"narHash": "sha256-nSTIB7JeJGBGsvtqlyfhUByh/isyK1nfOq2YMxUOFJQ=",
"owner": "fricklerhandwerk",
"repo": "git-hooks",
"rev": "99a78fcf7dc03ba7b1d5c00af109c1e28ced3490",
"type": "github"
},
"original": {
"owner": "fricklerhandwerk",
"repo": "git-hooks",
"type": "github"
}
},
"nixlib": {
"locked": {
"lastModified": 1712450863,
@@ -149,7 +133,6 @@
"inputs": {
"disko": "disko",
"flake-parts": "flake-parts",
"git-hooks": "git-hooks",
"nixos-generators": "nixos-generators",
"nixos-images": "nixos-images",
"nixpkgs": "nixpkgs",

View File

@@ -21,8 +21,6 @@
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
treefmt-nix.url = "github:numtide/treefmt-nix";
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
git-hooks.url = "github:fricklerhandwerk/git-hooks";
git-hooks.flake = false;
};
outputs =

View File

@@ -122,7 +122,7 @@ in
cores = lib.mkOption {
type = lib.types.ints.positive;
default = 1;
description = lib.mdDoc ''
description = ''
Specify the number of cores the guest is permitted to use.
The number can be higher than the available cores on the
host system.
@@ -132,7 +132,7 @@ in
memorySize = lib.mkOption {
type = lib.types.ints.positive;
default = 1024;
description = lib.mdDoc ''
description = ''
The memory size in megabytes of the virtual machine.
'';
};
@@ -140,7 +140,7 @@ in
graphics = lib.mkOption {
type = lib.types.bool;
default = true;
description = lib.mdDoc ''
description = ''
Whether to run QEMU with a graphics window, or in nographic mode.
Serial console will be enabled on both settings, but this will
change the preferred console.
@@ -150,7 +150,7 @@ in
waypipe = lib.mkOption {
type = lib.types.bool;
default = false;
description = lib.mdDoc ''
description = ''
Whether to use waypipe for native wayland passthrough, or not.
'';
};

View File

@@ -81,7 +81,7 @@ in
};
};
settings = lib.mkOption {
description = lib.mdDoc "override the network config in /var/lib/zerotier/bla/$network.json";
description = "override the network config in /var/lib/zerotier/bla/$network.json";
type = lib.types.submodule { freeformType = (pkgs.formats.json { }).type; };
};
};

View File

@@ -54,7 +54,7 @@ class AppendOptionAction(argparse.Action):
def create_parser(prog: str | None = None) -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
prog=prog,
description="cLAN tool",
description="The clan cli tool.",
epilog=(
"""
Online reference for the clan cli tool: https://docs.clan.lol/reference/cli/
@@ -126,6 +126,7 @@ For more detailed information, visit: https://docs.clan.lol/getting-started/back
parser_flake = subparsers.add_parser(
"flakes",
help="create a clan flake inside the current directory",
description="create a clan flake inside the current directory",
epilog=(
"""
Examples:
@@ -143,6 +144,7 @@ For more detailed information, visit: https://docs.clan.lol/getting-started
parser_config = subparsers.add_parser(
"config",
help="set nixos configuration",
description="set nixos configuration",
epilog=(
"""
"""
@@ -151,12 +153,32 @@ For more detailed information, visit: https://docs.clan.lol/getting-started
)
config.register_parser(parser_config)
parser_ssh = subparsers.add_parser("ssh", help="ssh to a remote machine")
parser_ssh = subparsers.add_parser(
"ssh",
help="ssh to a remote machine",
description="ssh to a remote machine",
epilog=(
"""
This subcommand allows seamless ssh access to the nixos-image builders.
Examples:
$ clan ssh [ssh_args ...] --json [JSON]
Will ssh in to the machine based on the deployment information contained in
the json string. [JSON] can either be a json formatted string itself, or point
towards a file containing the deployment information
For more detailed information, visit: https://docs.clan.lol/getting-started/deploy
"""
),
formatter_class=argparse.RawTextHelpFormatter,
)
ssh_cli.register_parser(parser_ssh)
parser_secrets = subparsers.add_parser(
"secrets",
help="manage secrets",
description="manage secrets",
epilog=(
"""
This subcommand provides an interface to secret facts.
@@ -180,6 +202,7 @@ For more detailed information, visit: https://docs.clan.lol/getting-started/secr
parser_facts = subparsers.add_parser(
"facts",
help="manage facts",
description="manage facts",
epilog=(
"""
@@ -216,6 +239,7 @@ For more detailed information, visit: https://docs.clan.lol/getting-started/secr
parser_machine = subparsers.add_parser(
"machines",
help="manage machines and their configuration",
description="manage machines and their configuration",
epilog=(
"""
This subcommand provides an interface to machines managed by clan.
@@ -239,14 +263,22 @@ For more detailed information, visit: https://docs.clan.lol/getting-started/depl
)
machines.register_parser(parser_machine)
parser_vms = subparsers.add_parser("vms", help="manage virtual machines")
parser_vms = subparsers.add_parser(
"vms", help="manage virtual machines", description="manage virtual machines"
)
vms.register_parser(parser_vms)
parser_history = subparsers.add_parser("history", help="manage history")
parser_history = subparsers.add_parser(
"history",
help="manage history",
description="manage history",
)
history.register_parser(parser_history)
parser_flash = subparsers.add_parser(
"flash", help="flash machines to usb sticks or into isos"
"flash",
help="flash machines to usb sticks or into isos",
description="flash machines to usb sticks or into isos",
)
flash.register_parser(parser_flash)

View File

@@ -140,3 +140,23 @@ def run(
raise ClanCmdError(cmd_out)
return cmd_out
def run_no_stdout(
cmd: list[str],
*,
env: dict[str, str] | None = None,
cwd: Path = Path.cwd(),
log: Log = Log.STDERR,
check: bool = True,
error_msg: str | None = None,
) -> CmdOut:
"""
Like run, but automatically suppresses stdout, if not in DEBUG log level.
If in DEBUG log level the stdout of commands will be shown.
"""
if logging.getLogger(__name__.split(".")[0]).isEnabledFor(logging.DEBUG):
return run(cmd, env=env, log=log, check=check, error_msg=error_msg)
else:
log = Log.NONE
return run(cmd, env=env, log=log, check=check, error_msg=error_msg)

View File

@@ -53,7 +53,7 @@ def inspect_flake(flake_url: str | Path, machine_name: str) -> FlakeConfig:
gcroot_icon: Path = machine_gcroot(flake_url=str(flake_url)) / vm.machine_name
nix_add_to_gcroots(vm.machine_icon, gcroot_icon)
# Get the cLAN name
# Get the Clan name
cmd = nix_eval(
[
f'{flake_url}#clanInternals.machines."{system}"."{machine_name}".config.clanCore.clanName'
@@ -70,7 +70,7 @@ def inspect_flake(flake_url: str | Path, machine_name: str) -> FlakeConfig:
)
res = run_cmd(cmd)
# If the icon is null, no icon is set for this cLAN
# If the icon is null, no icon is set for this Clan
if res == "null":
icon_path = None
else:
@@ -113,7 +113,7 @@ def inspect_command(args: argparse.Namespace) -> None:
res = inspect_flake(
flake_url=inspect_options.flake, machine_name=inspect_options.machine
)
print("cLAN name:", res.clan_name)
print("Clan name:", res.clan_name)
print("Icon:", res.icon)
print("Description:", res.description)
print("Last updated:", res.last_updated)

View File

@@ -17,7 +17,26 @@ def register_parser(parser: argparse.ArgumentParser) -> None:
required=True,
)
update_parser = subparser.add_parser("update", help="Update a machine")
update_parser = subparser.add_parser(
"update",
help="Update a machine",
epilog=(
"""
This subcommand provides an interface to update machines managed by clan.
Examples:
$ clan machines update [MACHINES]
Will update the specified machine [MACHINE], if [MACHINE] is omitted, the command
will attempt to update every configured machine.
To exclude machines being updated `clan.deployment.requireExplicitUpdate = true;`
can be set in the machine config.
For more detailed information, visit: https://docs.clan.lol/getting-started/deploy
"""
),
formatter_class=argparse.RawTextHelpFormatter,
)
register_update_parser(update_parser)
create_parser = subparser.add_parser("create", help="Create a machine")
@@ -26,7 +45,21 @@ def register_parser(parser: argparse.ArgumentParser) -> None:
delete_parser = subparser.add_parser("delete", help="Delete a machine")
register_delete_parser(delete_parser)
list_parser = subparser.add_parser("list", help="List machines")
list_parser = subparser.add_parser(
"list",
help="List machines",
epilog=(
"""
This subcommand lists all machines managed by this clan.
Examples:
$ clan machines list
Lists all the machines and their descriptions.
"""
),
formatter_class=argparse.RawTextHelpFormatter,
)
register_list_parser(list_parser)
install_parser = subparser.add_parser(
@@ -37,5 +70,23 @@ def register_parser(parser: argparse.ArgumentParser) -> None:
The target must be a Linux based system reachable via SSH.
Installing a machine means overwriting the target's disk.
""",
epilog=(
"""
This subcommand provides an interface to install machines managed by clan.
Examples:
$ clan machines install [MACHINE] [TARGET_HOST]
Will install the specified machine [MACHINE], to the specified [TARGET_HOST].
$ clan machines install [MACHINE] --json [JSON]
Will install the specified machine [MACHINE] to the host exposed by
the deployment information of the [JSON] deployment string.
For information on how to set up the installer see: https://docs.clan.lol/getting-started/installer/
For more detailed information, visit: https://docs.clan.lol/getting-started/deploy
"""
),
formatter_class=argparse.RawTextHelpFormatter,
)
register_install_parser(install_parser)

View File

@@ -6,7 +6,7 @@ from pathlib import Path
from clan_cli.api import API
from ..cmd import Log, run
from ..cmd import run_no_stdout
from ..nix import nix_config, nix_eval
log = logging.getLogger(__name__)
@@ -34,10 +34,7 @@ def list_machines(flake_url: str | Path, debug: bool) -> dict[str, MachineInfo]:
]
)
if not debug:
proc = run(cmd, log=Log.NONE)
else:
proc = run(cmd)
proc = run_no_stdout(cmd)
res = proc.stdout.strip()
machines_dict = json.loads(res)

View File

@@ -10,7 +10,7 @@ from clan_cli.clan_uri import ClanURI, MachineData
from clan_cli.dirs import vm_state_dir
from clan_cli.qemu.qmp import QEMUMonitorProtocol
from ..cmd import run
from ..cmd import run_no_stdout
from ..errors import ClanError
from ..nix import nix_build, nix_config, nix_eval, nix_metadata
from ..ssh import Host, parse_deployment_address
@@ -197,7 +197,7 @@ class Machine:
config_json.flush()
file_info = json.loads(
run(
run_no_stdout(
nix_eval(
[
"--impure",
@@ -247,10 +247,10 @@ class Machine:
]
if method == "eval":
output = run(nix_eval(args)).stdout.strip()
output = run_no_stdout(nix_eval(args)).stdout.strip()
return output
elif method == "build":
outpath = run(nix_build(args)).stdout.strip()
outpath = run_no_stdout(nix_build(args)).stdout.strip()
return Path(outpath)
else:
raise ValueError(f"Unknown method {method}")

View File

@@ -106,7 +106,7 @@ def nix_shell(packages: list[str], cmd: list[str]) -> list[str]:
if os.environ.get("IN_NIX_SANDBOX"):
return cmd
return [
*nix_command(["shell", "--offline", "--inputs-from", f"{nixpkgs_flake()!s}"]),
*nix_command(["shell", "--inputs-from", f"{nixpkgs_flake()!s}"]),
*packages,
"-c",
*cmd,

View File

@@ -83,7 +83,7 @@ let
cp -r ${./.} $out
chmod -R +w $out
rm $out/clan_cli/config/jsonschema
ln -s ${nixpkgs'} $out/clan_cli/nixpkgs
ln -sf ${nixpkgs'} $out/clan_cli/nixpkgs
cp -r ${../../lib/jsonschema} $out/clan_cli/config/jsonschema
'';
@@ -101,7 +101,7 @@ let
outputs = _inputs: { };
}
EOF
ln -s ${nixpkgs} $out/path
ln -sf ${nixpkgs} $out/path
nix flake update $out \
--store ./. \
--extra-experimental-features 'nix-command flakes'

View File

@@ -22,7 +22,7 @@ class Option:
md_li += indent_next(
f"\n{self.description.strip()}" if self.description else ""
)
md_li += indent_next(f"\n{self.epilog.strip()}" if self.epilog else "")
# md_li += indent_next(f"\n{self.epilog.strip()}" if self.epilog else "")
return md_li
@@ -82,13 +82,54 @@ class Category:
md_li += indent_all(
f"{self.description.strip()}\n" if self.description else "", 4
)
md_li += "\n"
md_li += indent_all(f"{self.epilog.strip()}\n" if self.epilog else "", 4)
md_li += "\n"
return md_li
def epilog_to_md(text: str) -> str:
"""
Convert the epilog to md
"""
after_examples = False
md = ""
# md += text
for line in text.split("\n"):
if line.strip() == "Examples:":
after_examples = True
md += "### Examples"
md += "\n"
else:
if after_examples:
if line.strip().startswith("$"):
md += f"`{line}`"
md += "\n"
md += "\n"
else:
if contains_https_link(line):
line = convert_to_markdown_link(line)
md += line
md += "\n"
else:
md += line
md += "\n"
return md
import re
def contains_https_link(line: str) -> bool:
pattern = r"https://\S+"
return re.search(pattern, line) is not None
def convert_to_markdown_link(line: str) -> str:
pattern = r"(https://\S+)"
# Replacement pattern to convert it to a Markdown link
return re.sub(pattern, r"[\1](\1)", line)
def indent_next(text: str, indent_size: int = 4) -> str:
"""
Indent all lines in a string except the first line.
@@ -136,7 +177,7 @@ def get_subcommands(
continue
if isinstance(action, argparse._SubParsersAction):
continue # Subparsers handled sperately
continue # Subparsers handled separately
option_strings = ", ".join(action.option_strings)
if option_strings:
@@ -178,7 +219,7 @@ def get_subcommands(
Category(
title=f"{parent} {name}",
description=subparser.description,
epilog=subparser.epilog,
# epilog=subparser.epilog,
level=level,
options=_options,
positionals=_positionals,
@@ -222,6 +263,7 @@ def collect_commands() -> list[Category]:
options=_options,
positionals=_positionals,
subcommands=_subcommands,
epilog=subparser.epilog,
level=1,
)
)
@@ -280,6 +322,7 @@ def build_command_reference() -> None:
markdown = files.get(folder / f"{filename}.md", "")
markdown += f"{'#'*(cmd.level)} {cmd.title.capitalize()}\n\n"
markdown += f"{cmd.description}\n\n" if cmd.description else ""
# usage: clan vms run [-h] machine
@@ -320,6 +363,8 @@ def build_command_reference() -> None:
markdown += indent_all(commands_fmt)
markdown += "\n"
markdown += f"{epilog_to_md(cmd.epilog)}\n\n" if cmd.epilog else ""
files[folder / f"{filename}.md"] = markdown
for fname, content in files.items():

View File

@@ -26,7 +26,7 @@ log = logging.getLogger(__name__)
class MainWindow(Adw.ApplicationWindow):
def __init__(self, config: ClanConfig) -> None:
super().__init__()
self.set_title("cLAN Manager")
self.set_title("Clan Manager")
self.set_default_size(980, 850)
overlay = ToastOverlay.use().overlay

View File

@@ -27,7 +27,7 @@ let
name = "org.clan.vm-manager";
exec = "clan-vm-manager %u";
icon = ./clan_vm_manager/assets/clan_white.png;
desktopName = "cLAN Manager";
desktopName = "Clan Manager";
startupWMClass = "clan";
mimeTypes = [ "x-scheme-handler/clan" ];
};

View File

@@ -0,0 +1,42 @@
{
lib,
coreutils,
nil,
nixd,
nixpkgs-fmt,
direnv,
vscode-extensions,
vscode-with-extensions,
vscodium,
writeShellApplication,
}:
let
codium = vscode-with-extensions.override {
vscode = vscodium;
vscodeExtensions = [
vscode-extensions.jnoortheen.nix-ide
vscode-extensions.mkhl.direnv
];
};
in
writeShellApplication {
name = "clan-edit-codium";
runtimeInputs = [
coreutils
nil
nixd
nixpkgs-fmt
direnv
];
text = ''
set -eux
DATA_DIR="''${XDG_CACHE_HOME:-$HOME/.cache}/clan-edit-codium"
SETTINGS="$DATA_DIR"/User/settings.json
${coreutils}/bin/mkdir -p "$DATA_DIR/User"
cat ${./settings.json} > "$SETTINGS"
exec ${lib.getExe codium} --user-data-dir "$DATA_DIR" "$@"
'';
derivationArgs.passthru.completion-options = import ./completion-options.nix;
}

View File

@@ -0,0 +1,17 @@
let
flake = builtins.getFlake "https://git.clan.lol/clan/clan-core/archive/main.tar.gz";
nixpkgs = flake.inputs.nixpkgs;
pkgs = nixpkgs.legacyPackages.${builtins.currentSystem};
clanCore = flake.outputs.nixosModules.clanCore;
clanModules = flake.outputs.clanModules;
allNixosModules = (import "${nixpkgs}/nixos/modules/module-list.nix") ++ [
"${nixpkgs}/nixos/modules/misc/assertions.nix"
{ nixpkgs.hostPlatform = "x86_64-linux"; }
];
clanCoreNixosModules = [
clanCore
# { clanCore.clanDir = ./.; }
] ++ allNixosModules ++ (builtins.attrValues clanModules);
clanCoreNixos = pkgs.nixos { imports = clanCoreNixosModules; };
in
clanCoreNixos.options

4
pkgs/editor/default.nix Normal file
View File

@@ -0,0 +1,4 @@
{ pkgs }:
{
clan-edit-codium = pkgs.callPackage ./clan-edit-codium.nix;
}

26
pkgs/editor/settings.json Normal file
View File

@@ -0,0 +1,26 @@
{
"security.workspace.trust.enabled": false,
"nix.enableLanguageServer": true,
"nix.serverPath": "nixd",
"nix.formatterPath": "nixpkgs-fmt",
"nix.serverSettings": {
"nixd": {
"formatting": {
"command": "nixpkgs-fmt"
},
"options": {
"nixos": {
"expr": "(let pkgs = import <nixpkgs> { }; in (pkgs.lib.evalModules { modules
= (import <nixpkgs/nixos/modules/module-list.nix>) ++ [ ({...}: {
nixpkgs.hostPlatform = builtins.currentSystem;} ) ] ; })).options"
},
"clan": {
"expr": "let pkgs = import <nixpkgs> { }; flake = builtins.getFlake \"https://git.clan.lol/clan/clan-core/archive/main.tar.gz\"; clanCore = flake.outputs.nixosModules.clanCore; clanModules = flake.outputs.clanModules; allNixosModules = (import <nixpkgs/nixos/modules/module-list.nix>) ++ [<nixpkgs/nixos/modules/misc/assertions.nix> {nixpkgs.hostPlatform = \"x86_64-linux\";}]; clanCoreNixosModules = [clanCore] ++ allNixosModules ++ (builtins.attrValues clanModules); clanCoreNixos = pkgs.nixos { imports = clanCoreNixosModules;}; in clanCoreNixos.options"
},
"clan-core": {
"expr": "(builtins.getFlake \"/home/kenji/git/clan-projects/clan-core\").packages.x86_64-linux.editor.passthru.completion-options",
},
}
}
}
}

View File

@@ -7,6 +7,7 @@
./installer/flake-module.nix
./schemas/flake-module.nix
./webview-ui/flake-module.nix
./gui-installer/flake-module.nix
];
perSystem =
@@ -25,6 +26,7 @@
moonlight-sunshine-accept = pkgs.callPackage ./moonlight-sunshine-accept { };
merge-after-ci = pkgs.callPackage ./merge-after-ci { inherit (config.packages) tea-create-pr; };
pending-reviews = pkgs.callPackage ./pending-reviews { };
editor = pkgs.callPackage ./editor/clan-edit-codium.nix { };
}
// lib.optionalAttrs pkgs.stdenv.isLinux {
wayland-proxy-virtwl = pkgs.callPackage ./wayland-proxy-virtwl { };

View File

@@ -0,0 +1,33 @@
{
perSystem =
{ pkgs, ... }:
let
nfpmConfig = pkgs.writeText "clan-nfpm-config.yaml" (
builtins.toJSON {
name = "clan-gui-installer";
contents = [
{
src = "${./gui-installer.sh}";
dst = "/usr/bin/clan-vm-manager";
}
];
}
);
installerFor =
packager:
pkgs.runCommand "gui-installer" { } ''
mkdir build
cd build
${pkgs.nfpm}/bin/nfpm package --config ${nfpmConfig} --packager ${packager}
mkdir $out
mv * $out/
'';
in
{
packages.gui-installer-apk = installerFor "apk";
packages.gui-installer-archlinux = installerFor "archlinux";
packages.gui-installer-deb = installerFor "deb";
packages.gui-installer-rpm = installerFor "rpm";
};
}

View File

@@ -0,0 +1,54 @@
#! /bin/sh
# create temp dir and ensure it is always cleaned
trap 'clean_temp_dir' EXIT
temp_dir=$(mktemp -d)
clean_temp_dir() {
rm -rf "$temp_dir"
}
is_nix_installed() {
if [ -n "$(command -v nix)" ]; then
return 0
else
return 1
fi
}
install_nix() {
curl --proto '=https' --tlsv1.2 -sSf -L \
https://install.determinate.systems/nix \
> "$temp_dir"/install_nix.sh
NIX_INSTALLER_DIAGNOSTIC_ENDPOINT="" sh "$temp_dir"/install_nix.sh install
}
ask_then_install_nix() {
echo "Clan requires Nix to be installed. Would you like to install it now? (y/n)"
read -r response
if [ "$response" = "y" ]; then
install_nix
else
echo "Clan cannot run without Nix. Exiting."
exit 1
fi
}
ensure_nix_installed() {
if ! is_nix_installed; then
ask_then_install_nix
fi
}
start_clan_gui() {
exec nix run \
https://git.clan.lol/clan/clan-core/archive/main.tar.gz#clan-vm-manager \
--extra-experimental-features flakes nix-command -- "$@"
}
main() {
ensure_nix_installed
start_clan_gui "$@"
}
main "$@"

28
scripts/pre-commit Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
# To install:
# ln -sf ../../scripts/pre-commit .git/hooks/pre-commit
set -o errexit
set -o nounset
set -o pipefail
readarray staged < <(git diff --name-only --cached)
[[ ${#staged[@]} = 0 ]] && exit
unstash() {
local ret=$?
set +e
git stash pop -q
exit "$ret"
}
git stash push --quiet --keep-index --message "pre-commit"
trap unstash EXIT
nix fmt
{
changed=$(git diff --name-only --exit-code);
status=$?;
} || true
if [[ $status -ne 0 ]]; then
exec 1>&2
echo Files changed by pre-commit hook:
echo "$changed"
exit $status
fi

View File

@@ -85,9 +85,9 @@
};
in
{
# all machines managed by cLAN
# all machines managed by Clan
inherit (clan) nixosConfigurations clanInternals;
# add the cLAN cli tool to the dev shell
# add the Clan cli tool to the dev shell
devShells.${system}.default = pkgs.mkShell {
packages = [ clan-core.packages.${system}.clan-cli ];
};