Compare commits
33 Commits
clan/examp
...
complete-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66aa97ad8f | ||
|
|
c252f11c1f | ||
|
|
f1f040397d | ||
|
|
418e9937cb | ||
|
|
c34664429c | ||
|
|
6fe5928297 | ||
|
|
eee99730d1 | ||
|
|
9394760e3b | ||
|
|
a0b0e1a0ac | ||
|
|
dbaa26ccaa | ||
|
|
d1591d4485 | ||
|
|
c68a8306ba | ||
|
|
ec9f605004 | ||
|
|
e60efea1f7 | ||
|
|
efacb7f184 | ||
|
|
67275aac63 | ||
|
|
a704a05b15 | ||
|
|
01aafc520d | ||
|
|
c0a54f539a | ||
|
|
1df4e361f7 | ||
|
|
e8bd5ad24b | ||
|
|
775f993ecc | ||
|
|
0e1478edcd | ||
|
|
bfc1203a8a | ||
|
|
2bd8b144b9 | ||
|
|
b52b2221b0 | ||
|
|
64adf17368 | ||
|
|
509d8c1dae | ||
|
|
295de17640 | ||
|
|
b158c2706f | ||
|
|
750979c988 | ||
|
|
6d7849a03c | ||
|
|
f46fd3ace6 |
@@ -1,4 +1,4 @@
|
|||||||
# Contributing to cLAN
|
# Contributing to Clan
|
||||||
|
|
||||||
## Live-reloading documentation
|
## Live-reloading documentation
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Clan Core Repository
|
# 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?
|
## Why Clan?
|
||||||
|
|
||||||
|
|||||||
10
devShell.nix
10
devShell.nix
@@ -1,4 +1,4 @@
|
|||||||
{ inputs, ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
perSystem =
|
perSystem =
|
||||||
{
|
{
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
writers = pkgs.callPackage ./pkgs/builders/script-writers.nix { };
|
writers = pkgs.callPackage ./pkgs/builders/script-writers.nix { };
|
||||||
inherit (pkgs.callPackage inputs.git-hooks { }) lib;
|
|
||||||
|
|
||||||
ansiEscapes = {
|
ansiEscapes = {
|
||||||
reset = ''\033[0m'';
|
reset = ''\033[0m'';
|
||||||
@@ -22,11 +21,6 @@
|
|||||||
select-shell = writers.writePython3Bin "select-shell" {
|
select-shell = writers.writePython3Bin "select-shell" {
|
||||||
flakeIgnore = [ "E501" ];
|
flakeIgnore = [ "E501" ];
|
||||||
} ./pkgs/scripts/select-shell.py;
|
} ./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
|
in
|
||||||
{
|
{
|
||||||
devShells.default = pkgs.mkShell {
|
devShells.default = pkgs.mkShell {
|
||||||
@@ -41,8 +35,6 @@
|
|||||||
config.treefmt.build.wrapper
|
config.treefmt.build.wrapper
|
||||||
];
|
];
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
${install-pre-commit-hook}
|
|
||||||
|
|
||||||
echo -e "${ansiEscapes.green}switch to another dev-shell using: select-shell${ansiEscapes.reset}"
|
echo -e "${ansiEscapes.green}switch to another dev-shell using: select-shell${ansiEscapes.reset}"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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.
|
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.
|
- 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)
|
- 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)
|
- 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.
|
- 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 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
|
- 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.
|
- 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.
|
- 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
|
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
|
- 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
|
- 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.
|
- After accepting, all new software and services to interact with the new photoprism service will be installed automatically.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Joining a cLAN network
|
# Joining a Clan network
|
||||||
|
|
||||||
## General Description
|
## General Description
|
||||||
|
|
||||||
@@ -8,13 +8,13 @@ Joining a self-hosted infrastructure involves connecting to a network, server, o
|
|||||||
|
|
||||||
### Story 1: Joining a private network
|
### 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.
|
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
|
### 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.
|
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
|
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
|
## Challenges
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# cLAN module maintaining
|
# Clan module maintaining
|
||||||
|
|
||||||
## General Description
|
## 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. 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.
|
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.
|
||||||
|
|||||||
@@ -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.
|
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
|
!!! info
|
||||||
Don't worry — if you've already made one before, this step won't change or overwrite it.
|
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
|
!!! warning
|
||||||
Make sure to keep a safe backup of the private key you've just created.
|
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
|
!!! note
|
||||||
It's safe to add any secrets created by the clan CLI and placed in your repository to version control systems like `git`.
|
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
|
### Add Your Public Key
|
||||||
|
|
||||||
```bash
|
```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.
|
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
|
### 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
|
To add machines/users to an existing secret use:
|
||||||
clan secrets set --machine <machine1> --machine <machine2> --user <user1> --user <user2> <secret_name>
|
|
||||||
```
|
|
||||||
You can also just add machines/users to existing secrets:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
clan secrets machines add-secret <machine_name> <secret_name>
|
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
|
## Advanced
|
||||||
|
|
||||||
In this section we go into more advanced secret management topics.
|
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.
|
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
|
## Indepth Explanation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The secrets system conceptually knows two different entities:
|
The secrets system conceptually knows two different entities:
|
||||||
|
|
||||||
- **Machine**: consumes secrets
|
- **Machine**: consumes secrets
|
||||||
|
|||||||
25
eval-options.sh
Executable file
25
eval-options.sh
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# nix eval \
|
||||||
|
# --json \
|
||||||
|
# --impure \
|
||||||
|
# --expr \
|
||||||
|
# "(let pkgs = import <nixpkgs> { }; in (pkgs.lib.evalModules { modules = (import <nixpkgs/nixos/modules/module-list.nix>) ++ [ ({...}: { nixpkgs.hostPlatform = builtins.currentSystem;} ) ] ; })).options"
|
||||||
|
|
||||||
|
# nix eval \
|
||||||
|
# --json \
|
||||||
|
# --impure \
|
||||||
|
# --expr \
|
||||||
|
# "(let pkgs = import <nixpkgs> { }; in (pkgs.lib.evalModules { modules = (import <nixpkgs/nixos/modules/module-list.nix>) ++ [(import <nixpkgs/nixos/modules/misc/assertions.nix>)] ++ [ (builtins.getFlake https://git.clan.lol/clan/clan-core/archive/main.tar.gz).clanModules (builtins.getFlake https://git.clan.lol/clan/clan-core/archive/main.tar.gz).nixosModules.clanCore ({...}: { nixpkgs.hostPlatform = builtins.currentSystem;} ) ] ; })).options"
|
||||||
|
|
||||||
|
# nix eval \
|
||||||
|
# --json \
|
||||||
|
# --impure \
|
||||||
|
# --expr \
|
||||||
|
# "(let pkgs = import <nixpkgs> { }; allNixosModules = (import <nixpkgs/nixos/modules/module-list.nix>) ++ [(import <nixpkgs/nixos/modules/misc/assertions.nix>) { nixpkgs.hostPlatform = \"x86_64-linux\"; }]; in (pkgs.lib.evalModules { modules = allNixosModules ++ [ (builtins.getFlake https://git.clan.lol/clan/clan-core/archive/main.tar.gz).clanModules (builtins.getFlake https://git.clan.lol/clan/clan-core/archive/main.tar.gz).nixosModules.clanCore ({...}: { nixpkgs.hostPlatform = builtins.currentSystem;} ) ] ; })).options"
|
||||||
|
#
|
||||||
|
#
|
||||||
|
nix eval \
|
||||||
|
--json \
|
||||||
|
--impure \
|
||||||
|
--file \
|
||||||
|
./options.nix
|
||||||
17
flake.lock
generated
17
flake.lock
generated
@@ -40,22 +40,6 @@
|
|||||||
"type": "github"
|
"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": {
|
"nixlib": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1712450863,
|
"lastModified": 1712450863,
|
||||||
@@ -149,7 +133,6 @@
|
|||||||
"inputs": {
|
"inputs": {
|
||||||
"disko": "disko",
|
"disko": "disko",
|
||||||
"flake-parts": "flake-parts",
|
"flake-parts": "flake-parts",
|
||||||
"git-hooks": "git-hooks",
|
|
||||||
"nixos-generators": "nixos-generators",
|
"nixos-generators": "nixos-generators",
|
||||||
"nixos-images": "nixos-images",
|
"nixos-images": "nixos-images",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
|
|||||||
@@ -21,8 +21,6 @@
|
|||||||
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
|
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
|
||||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||||
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
|
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
git-hooks.url = "github:fricklerhandwerk/git-hooks";
|
|
||||||
git-hooks.flake = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs =
|
outputs =
|
||||||
|
|||||||
17
options.nix
Normal file
17
options.nix
Normal 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 = flake.inputs.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
|
||||||
@@ -52,7 +52,17 @@ class AppendOptionAction(argparse.Action):
|
|||||||
|
|
||||||
|
|
||||||
def create_parser(prog: str | None = None) -> argparse.ArgumentParser:
|
def create_parser(prog: str | None = None) -> argparse.ArgumentParser:
|
||||||
parser = argparse.ArgumentParser(prog=prog, description="cLAN tool")
|
parser = argparse.ArgumentParser(
|
||||||
|
prog=prog,
|
||||||
|
description="The clan cli tool.",
|
||||||
|
epilog=(
|
||||||
|
"""
|
||||||
|
Online reference for the clan cli tool: https://docs.clan.lol/reference/cli/
|
||||||
|
For more detailed information, visit: https://docs.clan.lol
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--debug",
|
"--debug",
|
||||||
@@ -90,39 +100,185 @@ def create_parser(prog: str | None = None) -> argparse.ArgumentParser:
|
|||||||
"backups",
|
"backups",
|
||||||
help="manage backups of clan machines",
|
help="manage backups of clan machines",
|
||||||
description="manage backups of clan machines",
|
description="manage backups of clan machines",
|
||||||
|
epilog=(
|
||||||
|
"""
|
||||||
|
This subcommand provides an interface to backups that clan machines expose.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ clan backups list [MACHINE]
|
||||||
|
List backups for the machine [MACHINE]
|
||||||
|
|
||||||
|
$ clan backups create [MACHINE]
|
||||||
|
Create a backup for the machine [MACHINE].
|
||||||
|
|
||||||
|
$ clan backups restore [MACHINE] [PROVIDER] [NAME]
|
||||||
|
The backup to restore for the machine [MACHINE] with the configured [PROVIDER]
|
||||||
|
with the name [NAME].
|
||||||
|
|
||||||
|
For more detailed information, visit: https://docs.clan.lol/getting-started/backups/
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
)
|
)
|
||||||
backups.register_parser(parser_backups)
|
backups.register_parser(parser_backups)
|
||||||
|
|
||||||
parser_flake = subparsers.add_parser(
|
parser_flake = subparsers.add_parser(
|
||||||
"flakes", help="create a clan flake inside the current directory"
|
"flakes",
|
||||||
|
help="create a clan flake inside the current directory",
|
||||||
|
description="create a clan flake inside the current directory",
|
||||||
|
epilog=(
|
||||||
|
"""
|
||||||
|
Examples:
|
||||||
|
$ clan flakes create [DIR]
|
||||||
|
Will create a new clan flake in the specified directory and create it if it
|
||||||
|
doesn't exist yet. The flake will be created from a default template.
|
||||||
|
|
||||||
|
For more detailed information, visit: https://docs.clan.lol/getting-started
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
)
|
)
|
||||||
flakes.register_parser(parser_flake)
|
flakes.register_parser(parser_flake)
|
||||||
|
|
||||||
parser_config = subparsers.add_parser("config", help="set nixos configuration")
|
parser_config = subparsers.add_parser(
|
||||||
|
"config",
|
||||||
|
help="set nixos configuration",
|
||||||
|
description="set nixos configuration",
|
||||||
|
epilog=(
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
|
)
|
||||||
config.register_parser(parser_config)
|
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)
|
ssh_cli.register_parser(parser_ssh)
|
||||||
|
|
||||||
parser_secrets = subparsers.add_parser("secrets", help="manage secrets")
|
parser_secrets = subparsers.add_parser(
|
||||||
|
"secrets",
|
||||||
|
help="manage secrets",
|
||||||
|
description="manage secrets",
|
||||||
|
epilog=(
|
||||||
|
"""
|
||||||
|
This subcommand provides an interface to secret facts.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ clan secrets list [regex]
|
||||||
|
Will list secrets for all managed machines.
|
||||||
|
It accepts an optional regex, allowing easy filtering of returned secrets.
|
||||||
|
|
||||||
|
$ clan secrets get [SECRET]
|
||||||
|
Will display the content of the specified secret.
|
||||||
|
|
||||||
|
For more detailed information, visit: https://docs.clan.lol/getting-started/secrets/
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
|
)
|
||||||
secrets.register_parser(parser_secrets)
|
secrets.register_parser(parser_secrets)
|
||||||
|
|
||||||
parser_facts = subparsers.add_parser("facts", help="manage facts")
|
parser_facts = subparsers.add_parser(
|
||||||
|
"facts",
|
||||||
|
help="manage facts",
|
||||||
|
description="manage facts",
|
||||||
|
epilog=(
|
||||||
|
"""
|
||||||
|
|
||||||
|
This subcommand provides an interface to facts of clan machines.
|
||||||
|
Facts are artifacts that a service can generate.
|
||||||
|
There are public and secret facts.
|
||||||
|
Public facts can be referenced by other machines directly.
|
||||||
|
Public facts can include: ip addresses, public keys.
|
||||||
|
Secret facts can include: passwords, private keys.
|
||||||
|
|
||||||
|
A service is an included clan-module that implements facts generation functionality.
|
||||||
|
For example the zerotier module will generate private and public facts.
|
||||||
|
In this case the public fact will be the resulting zerotier-ip of the machine.
|
||||||
|
The secret fact will be the zerotier-identity-secret, which is used by zerotier
|
||||||
|
to prove the machine has control of the zerotier-ip.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ clan facts generate
|
||||||
|
Will generate facts for all machines.
|
||||||
|
|
||||||
|
$ clan facts generate --service [SERVICE] --regenerate
|
||||||
|
Will regenerate facts, if they are already generated for a specific service.
|
||||||
|
This is especially useful for resetting certain passwords while leaving the rest
|
||||||
|
of the facts for a machine in place.
|
||||||
|
|
||||||
|
For more detailed information, visit: https://docs.clan.lol/getting-started/secrets/
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
|
)
|
||||||
facts.register_parser(parser_facts)
|
facts.register_parser(parser_facts)
|
||||||
|
|
||||||
parser_machine = subparsers.add_parser(
|
parser_machine = subparsers.add_parser(
|
||||||
"machines", help="manage machines and their configuration"
|
"machines",
|
||||||
|
help="manage machines and their configuration",
|
||||||
|
description="manage machines and their configuration",
|
||||||
|
epilog=(
|
||||||
|
"""
|
||||||
|
This subcommand provides an interface to machines managed by clan.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ clan machines list
|
||||||
|
List all the machines managed by clan.
|
||||||
|
|
||||||
|
$ clan machines update [MACHINES]
|
||||||
|
Will update the specified machine [MACHINE], if [MACHINE] is omitted, the command
|
||||||
|
will attempt to update every configured machine.
|
||||||
|
|
||||||
|
$ clan machines install [MACHINES] [TARGET_HOST]
|
||||||
|
Will install the specified machine [MACHINE], to the specified [TARGET_HOST].
|
||||||
|
|
||||||
|
For more detailed information, visit: https://docs.clan.lol/getting-started/deploy
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
)
|
)
|
||||||
machines.register_parser(parser_machine)
|
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)
|
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)
|
history.register_parser(parser_history)
|
||||||
|
|
||||||
parser_flash = subparsers.add_parser(
|
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)
|
flash.register_parser(parser_flash)
|
||||||
|
|
||||||
|
|||||||
@@ -140,3 +140,23 @@ def run(
|
|||||||
raise ClanCmdError(cmd_out)
|
raise ClanCmdError(cmd_out)
|
||||||
|
|
||||||
return 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)
|
||||||
|
|||||||
@@ -23,7 +23,42 @@ def register_parser(parser: argparse.ArgumentParser) -> None:
|
|||||||
register_list_parser(list_parser)
|
register_list_parser(list_parser)
|
||||||
|
|
||||||
parser_generate = subparser.add_parser(
|
parser_generate = subparser.add_parser(
|
||||||
"generate", help="generate secrets for machines if they don't exist yet"
|
"generate",
|
||||||
|
help="generate public and secret facts for machines",
|
||||||
|
epilog=(
|
||||||
|
"""
|
||||||
|
This subcommand allows control of the generation of facts.
|
||||||
|
Often this function will be invoked automatically on deploying machines,
|
||||||
|
but there are situations the user may want to have more granular control,
|
||||||
|
especially for the regeneration of certain services.
|
||||||
|
|
||||||
|
A service is an included clan-module that implements facts generation functionality.
|
||||||
|
For example the zerotier module will generate private and public facts.
|
||||||
|
In this case the public fact will be the resulting zerotier-ip of the machine.
|
||||||
|
The secret fact will be the zerotier-identity-secret, which is used by zerotier
|
||||||
|
to prove the machine has control of the zerotier-ip.
|
||||||
|
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ clan facts generate
|
||||||
|
Will generate facts for all machines.
|
||||||
|
|
||||||
|
$ clan facts generate [MACHINE]
|
||||||
|
Will generate facts for the specified machine.
|
||||||
|
|
||||||
|
$ clan facts generate [MACHINE] --service [SERVICE]
|
||||||
|
Will generate facts for the specified machine for the specified service.
|
||||||
|
|
||||||
|
$ clan facts generate --service [SERVICE] --regenerate
|
||||||
|
Will regenerate facts, if they are already generated for a specific service.
|
||||||
|
This is especially useful for resetting certain passwords while leaving the rest
|
||||||
|
of the facts for a machine in place.
|
||||||
|
|
||||||
|
For more detailed information, visit: https://docs.clan.lol/getting-started/secrets/
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
)
|
)
|
||||||
register_generate_parser(parser_generate)
|
register_generate_parser(parser_generate)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
gcroot_icon: Path = machine_gcroot(flake_url=str(flake_url)) / vm.machine_name
|
||||||
nix_add_to_gcroots(vm.machine_icon, gcroot_icon)
|
nix_add_to_gcroots(vm.machine_icon, gcroot_icon)
|
||||||
|
|
||||||
# Get the cLAN name
|
# Get the Clan name
|
||||||
cmd = nix_eval(
|
cmd = nix_eval(
|
||||||
[
|
[
|
||||||
f'{flake_url}#clanInternals.machines."{system}"."{machine_name}".config.clanCore.clanName'
|
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)
|
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":
|
if res == "null":
|
||||||
icon_path = None
|
icon_path = None
|
||||||
else:
|
else:
|
||||||
@@ -113,7 +113,7 @@ def inspect_command(args: argparse.Namespace) -> None:
|
|||||||
res = inspect_flake(
|
res = inspect_flake(
|
||||||
flake_url=inspect_options.flake, machine_name=inspect_options.machine
|
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("Icon:", res.icon)
|
||||||
print("Description:", res.description)
|
print("Description:", res.description)
|
||||||
print("Last updated:", res.last_updated)
|
print("Last updated:", res.last_updated)
|
||||||
|
|||||||
@@ -17,7 +17,26 @@ def register_parser(parser: argparse.ArgumentParser) -> None:
|
|||||||
required=True,
|
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)
|
register_update_parser(update_parser)
|
||||||
|
|
||||||
create_parser = subparser.add_parser("create", help="Create a machine")
|
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")
|
delete_parser = subparser.add_parser("delete", help="Delete a machine")
|
||||||
register_delete_parser(delete_parser)
|
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)
|
register_list_parser(list_parser)
|
||||||
|
|
||||||
install_parser = subparser.add_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.
|
The target must be a Linux based system reachable via SSH.
|
||||||
Installing a machine means overwriting the target's disk.
|
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)
|
register_install_parser(install_parser)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
from clan_cli.api import API
|
from clan_cli.api import API
|
||||||
|
|
||||||
from ..cmd import Log, run
|
from ..cmd import run_no_stdout
|
||||||
from ..nix import nix_config, nix_eval
|
from ..nix import nix_config, nix_eval
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
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_no_stdout(cmd)
|
||||||
proc = run(cmd, log=Log.NONE)
|
|
||||||
else:
|
|
||||||
proc = run(cmd)
|
|
||||||
|
|
||||||
res = proc.stdout.strip()
|
res = proc.stdout.strip()
|
||||||
machines_dict = json.loads(res)
|
machines_dict = json.loads(res)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from clan_cli.clan_uri import ClanURI, MachineData
|
|||||||
from clan_cli.dirs import vm_state_dir
|
from clan_cli.dirs import vm_state_dir
|
||||||
from clan_cli.qemu.qmp import QEMUMonitorProtocol
|
from clan_cli.qemu.qmp import QEMUMonitorProtocol
|
||||||
|
|
||||||
from ..cmd import run
|
from ..cmd import run_no_stdout
|
||||||
from ..errors import ClanError
|
from ..errors import ClanError
|
||||||
from ..nix import nix_build, nix_config, nix_eval, nix_metadata
|
from ..nix import nix_build, nix_config, nix_eval, nix_metadata
|
||||||
from ..ssh import Host, parse_deployment_address
|
from ..ssh import Host, parse_deployment_address
|
||||||
@@ -197,7 +197,7 @@ class Machine:
|
|||||||
config_json.flush()
|
config_json.flush()
|
||||||
|
|
||||||
file_info = json.loads(
|
file_info = json.loads(
|
||||||
run(
|
run_no_stdout(
|
||||||
nix_eval(
|
nix_eval(
|
||||||
[
|
[
|
||||||
"--impure",
|
"--impure",
|
||||||
@@ -247,10 +247,10 @@ class Machine:
|
|||||||
]
|
]
|
||||||
|
|
||||||
if method == "eval":
|
if method == "eval":
|
||||||
output = run(nix_eval(args)).stdout.strip()
|
output = run_no_stdout(nix_eval(args)).stdout.strip()
|
||||||
return output
|
return output
|
||||||
elif method == "build":
|
elif method == "build":
|
||||||
outpath = run(nix_build(args)).stdout.strip()
|
outpath = run_no_stdout(nix_build(args)).stdout.strip()
|
||||||
return Path(outpath)
|
return Path(outpath)
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Unknown method {method}")
|
raise ValueError(f"Unknown method {method}")
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ def nix_shell(packages: list[str], cmd: list[str]) -> list[str]:
|
|||||||
if os.environ.get("IN_NIX_SANDBOX"):
|
if os.environ.get("IN_NIX_SANDBOX"):
|
||||||
return cmd
|
return cmd
|
||||||
return [
|
return [
|
||||||
*nix_command(["shell", "--offline", "--inputs-from", f"{nixpkgs_flake()!s}"]),
|
*nix_command(["shell", "--inputs-from", f"{nixpkgs_flake()!s}"]),
|
||||||
*packages,
|
*packages,
|
||||||
"-c",
|
"-c",
|
||||||
*cmd,
|
*cmd,
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ let
|
|||||||
cp -r ${./.} $out
|
cp -r ${./.} $out
|
||||||
chmod -R +w $out
|
chmod -R +w $out
|
||||||
rm $out/clan_cli/config/jsonschema
|
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
|
cp -r ${../../lib/jsonschema} $out/clan_cli/config/jsonschema
|
||||||
'';
|
'';
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ let
|
|||||||
outputs = _inputs: { };
|
outputs = _inputs: { };
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
ln -s ${nixpkgs} $out/path
|
ln -sf ${nixpkgs} $out/path
|
||||||
nix flake update $out \
|
nix flake update $out \
|
||||||
--store ./. \
|
--store ./. \
|
||||||
--extra-experimental-features 'nix-command flakes'
|
--extra-experimental-features 'nix-command flakes'
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ log = logging.getLogger(__name__)
|
|||||||
class MainWindow(Adw.ApplicationWindow):
|
class MainWindow(Adw.ApplicationWindow):
|
||||||
def __init__(self, config: ClanConfig) -> None:
|
def __init__(self, config: ClanConfig) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.set_title("cLAN Manager")
|
self.set_title("Clan Manager")
|
||||||
self.set_default_size(980, 850)
|
self.set_default_size(980, 850)
|
||||||
|
|
||||||
overlay = ToastOverlay.use().overlay
|
overlay = ToastOverlay.use().overlay
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ let
|
|||||||
name = "org.clan.vm-manager";
|
name = "org.clan.vm-manager";
|
||||||
exec = "clan-vm-manager %u";
|
exec = "clan-vm-manager %u";
|
||||||
icon = ./clan_vm_manager/assets/clan_white.png;
|
icon = ./clan_vm_manager/assets/clan_white.png;
|
||||||
desktopName = "cLAN Manager";
|
desktopName = "Clan Manager";
|
||||||
startupWMClass = "clan";
|
startupWMClass = "clan";
|
||||||
mimeTypes = [ "x-scheme-handler/clan" ];
|
mimeTypes = [ "x-scheme-handler/clan" ];
|
||||||
};
|
};
|
||||||
|
|||||||
40
pkgs/editor/clan-edit-codium.nix
Normal file
40
pkgs/editor/clan-edit-codium.nix
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
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" "$@"
|
||||||
|
'';
|
||||||
|
}
|
||||||
4
pkgs/editor/default.nix
Normal file
4
pkgs/editor/default.nix
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{ pkgs }:
|
||||||
|
{
|
||||||
|
clan-edit-codium = pkgs.callPackage ./clan-edit-codium.nix;
|
||||||
|
}
|
||||||
23
pkgs/editor/settings.json
Normal file
23
pkgs/editor/settings.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"home-manager": {
|
||||||
|
"expr": "(builtins.getFlake \"github:nix-community/home-manager\").homeConfigurations.<name>.options"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
moonlight-sunshine-accept = pkgs.callPackage ./moonlight-sunshine-accept { };
|
moonlight-sunshine-accept = pkgs.callPackage ./moonlight-sunshine-accept { };
|
||||||
merge-after-ci = pkgs.callPackage ./merge-after-ci { inherit (config.packages) tea-create-pr; };
|
merge-after-ci = pkgs.callPackage ./merge-after-ci { inherit (config.packages) tea-create-pr; };
|
||||||
pending-reviews = pkgs.callPackage ./pending-reviews { };
|
pending-reviews = pkgs.callPackage ./pending-reviews { };
|
||||||
|
editor = pkgs.callPackage ./editor/clan-edit-codium.nix { };
|
||||||
}
|
}
|
||||||
// lib.optionalAttrs pkgs.stdenv.isLinux {
|
// lib.optionalAttrs pkgs.stdenv.isLinux {
|
||||||
wayland-proxy-virtwl = pkgs.callPackage ./wayland-proxy-virtwl { };
|
wayland-proxy-virtwl = pkgs.callPackage ./wayland-proxy-virtwl { };
|
||||||
|
|||||||
28
scripts/pre-commit
Executable file
28
scripts/pre-commit
Executable 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
|
||||||
@@ -85,9 +85,9 @@
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# all machines managed by cLAN
|
# all machines managed by Clan
|
||||||
inherit (clan) nixosConfigurations clanInternals;
|
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 {
|
devShells.${system}.default = pkgs.mkShell {
|
||||||
packages = [ clan-core.packages.${system}.clan-cli ];
|
packages = [ clan-core.packages.${system}.clan-cli ];
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user