Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions packages/mcl/src/main.d
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ alias supportedCommands = imported!`std.traits`.AliasSeq!(
cmds.shard_matrix,
cmds.host_info,
cmds.ci,
cmds.machine_create
cmds.machine,
cmds.config,
);

int main(string[] args)
Expand All @@ -42,7 +43,7 @@ int main(string[] args)
{

infof("Running %s task", cmd.bold);
command();
command(args[2..$]);
infof("Execution Succesfull");
return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/mcl/src/src/mcl/commands/ci.d
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import mcl.utils.json : toJSON;

Params params;

export void ci()
export void ci(string[] args)
{
params = parseEnv!Params;

Expand Down
4 changes: 2 additions & 2 deletions packages/mcl/src/src/mcl/commands/ci_matrix.d
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ shared static this()
params = parseEnv!Params;
}

export void ci_matrix()
export void ci_matrix(string[] args)
{
createResultDirs();
nixEvalForAllSystems().array.printTableForCacheStatus();
Expand Down Expand Up @@ -186,7 +186,7 @@ Package[] checkCacheStatus(Package[] packages)
return packages;
}

export void print_table()
export void print_table(string[] args)
{
createResultDirs();

Expand Down
125 changes: 125 additions & 0 deletions packages/mcl/src/src/mcl/commands/config.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
module mcl.commands.config;

import std.algorithm : canFind;
import std.array : array;
import std.process : ProcessPipes, Redirect, wait, environment;
import std.range : drop, front;
import std.stdio : writeln;
import std.string : indexOf;

import mcl.utils.env : optional, parseEnv;
import mcl.utils.fetch : fetchJson;
import mcl.utils.log : errorAndExit;
import mcl.utils.nix : nix, queryStorePath;
import mcl.utils.process : execute;
import mcl.utils.string : camelCaseToCapitalCase;

export void config(string[] args) {
if (args.length == 0) {
errorAndExit("Usage: mcl config <subcommand> [args]");
}
if (!checkRepo()) {
errorAndExit("This command must be run from a repository containing a NixOS machine configuration");
}

string subcommand = args.front;

switch (subcommand) {
case "sys":
sys(args.drop(1));
break;
case "home":
home(args.drop(1));
break;
case "start-vm":
startVM(args.drop(1));
break;
default:
errorAndExit("Unknown config subcommand " ~ subcommand ~ ". Supported subcommands: sys, home, start-vm");
break;
}
}

bool checkRepo()
{
const string[] validRepos = ["nixos-machine-config", "infra-lido"];
string remoteOriginUrl = execute(["git", "config", "--get", "remote.origin.url"], false);

foreach (string repo; validRepos) {
if (remoteOriginUrl.indexOf(repo) != -1) {
return true;
}
}
return false;
}

void executeCommand(string command) {
auto exec = execute!ProcessPipes(command, true, false, Redirect.stderrToStdout);
wait(exec.pid);
}

void edit(string type, string path) {
string editor = environment.get("EDITOR", "vim");
string user = environment.get("USER", "root");
writeln("Editing " ~ path ~ " configuration from: ", path);
final switch (type) {
case "system":
executeCommand(editor ~ " machines/*/" ~ path ~ "/*.nix");
break;
case "user":
executeCommand(editor~ " users/" ~ user ~ "/gitconfig " ~ "users/" ~ user ~ "/*.nix " ~ "users/" ~ user ~ "/home-"~path~"/*.nix");
break;
}
}

void sys(string[] args)
{
if ((args.length < 1 || args.length > 2) && !["apply", "edit"].canFind(args.front))
{
errorAndExit("Usage: mcl config sys apply or mcl config sys apply <machine-name>\n"~
" mcl config sys edit or mcl config sys edit <machine-name>");
}

string machineName = args.length > 1 ? args[1] : "";
final switch (args.front) {
case "apply":
writeln("Applying system configuration from: ", machineName);
executeCommand("just switch-system " ~ machineName);
break;
case "edit":
edit("system", machineName);
break;
}
}

void home(string[] args)
{
if ((args.length != 2) && args.front != "apply")
{
errorAndExit("Usage: mcl config home apply <desktop/server>\n"~
" mcl config home edit <desktop/server>");
}

auto type = args[1];
final switch (args.front) {
case "apply":
writeln("Applying home configuration from: ", type);
executeCommand("just switch-home " ~ type);
break;
case "edit":
edit("user", type);
break;
}
}

void startVM(string[] args)
{
if (args.length != 1)
{
errorAndExit("Usage: mcl config start-vm <vm-name>");
}

string vmName = args.front;
writeln("Starting VM: ", vmName);
executeCommand("just start-vm " ~ vmName);
}
2 changes: 1 addition & 1 deletion packages/mcl/src/src/mcl/commands/deploy_spec.d
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import mcl.utils.json : tryDeserializeFromJsonFile, writeJsonFile;

import mcl.commands.ci_matrix : flakeAttr, params, nixEvalJobs, SupportedSystem;

export void deploy_spec()
export void deploy_spec(string[] args)
{
const deploySpecFile = resultDir.buildPath("cachix-deploy-spec.json");

Expand Down
2 changes: 1 addition & 1 deletion packages/mcl/src/src/mcl/commands/get_fstab.d
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import mcl.utils.nix : queryStorePath, nix;
import mcl.utils.string : camelCaseToCapitalCase;
import mcl.utils.process : execute;

export void get_fstab()
export void get_fstab(string[] args)
{
const params = parseEnv!Params;
const machineStorePath = getCachixDeploymentStorePath(params);
Expand Down
2 changes: 1 addition & 1 deletion packages/mcl/src/src/mcl/commands/host_info.d
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ string[string] getProcInfo(string fileOrData, bool file = true)
return r;
}

export void host_info()
export void host_info(string[] args)
{
const Params params = parseEnv!Params;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module mcl.commands.machine_create;
module mcl.commands.machine;

import std;
import mcl.utils.log : prompt;
Expand Down Expand Up @@ -221,7 +221,7 @@ struct MachineConfiguration
}

void createMachine(MachineType machineType, string machineName, User user) {
auto infoJSON = execute(["ssh", params.sshPath, "sudo nix --experimental-features \\'nix-command flakes\\' --refresh --accept-flake-config run github:metacraft-labs/nixos-modules/feat/machine_create#mcl host_info"],false, false);
auto infoJSON = execute(["ssh", params.sshPath, "sudo nix --experimental-features \\'nix-command flakes\\' --refresh --accept-flake-config run github:metacraft-labs/nixos-modules/#mcl host_info"],false, false);
auto infoJSONParsed = infoJSON.parseJSON;
Info info = infoJSONParsed.fromJSON!Info;

Expand Down Expand Up @@ -377,10 +377,17 @@ void createMachineConfiguration()

Params params;

export void machine_create()
export void machine(string[] args)
{
params = parseEnv!Params;
createMachineConfiguration();
switch (args.front)
{
case "create":
createMachineConfiguration();
break;
default:
assert(0, "Unknown machine action: " ~ args.front);
}
}
struct Params
{
Expand Down
3 changes: 2 additions & 1 deletion packages/mcl/src/src/mcl/commands/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ public import mcl.commands.ci_matrix : ci_matrix, print_table;
public import mcl.commands.shard_matrix : shard_matrix;
public import mcl.commands.ci : ci;
public import mcl.commands.host_info : host_info;
public import mcl.commands.machine_create : machine_create;
public import mcl.commands.machine : machine;
public import mcl.commands.config : config;
2 changes: 1 addition & 1 deletion packages/mcl/src/src/mcl/commands/shard_matrix.d
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import mcl.utils.json : toJSON;
import mcl.utils.nix : nix;
import mcl.utils.path : createResultDirs, resultDir, rootDir;

export void shard_matrix()
export void shard_matrix(string[] args)
{
const params = parseEnv!Params;
auto matrix = generateShardMatrix();
Expand Down
9 changes: 9 additions & 0 deletions packages/mcl/src/src/mcl/utils/log.d
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
module mcl.utils.log;


void errorAndExit(string message) {
import core.stdc.stdlib: exit;
import std.stdio : stderr;

stderr.writeln(message);
exit(1);
}

T prompt(T)(string message, T[] options = [], string input = "unfilled")
{
import std.stdio : write, writeln, readln;
Expand Down
16 changes: 8 additions & 8 deletions packages/mcl/src/src/mcl/utils/process.d
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,34 @@ import mcl.utils.test;

import mcl.utils.tui : bold;

import std.process : ProcessPipes;
import std.process : ProcessPipes, Redirect;
import std.string : split, strip;
import core.sys.posix.unistd : geteuid;
import std.json : JSONValue, parseJSON;

bool isRoot() => geteuid() == 0;

T execute(T = string)(string args, bool printCommand = true, bool returnErr = false) if (is(T == string) || is(T == ProcessPipes) || is(T == JSONValue))
T execute(T = string)(string args, bool printCommand = true, bool returnErr = false, Redirect redirect = Redirect.all) if (is(T == string) || is(T == ProcessPipes) || is(T == JSONValue))
{
return execute!T(args.split(" "), printCommand, returnErr);
return execute!T(args.strip.split(" "), printCommand, returnErr, redirect);
}
T execute(T = string)(string[] args, bool printCommand = true, bool returnErr = false) if (is(T == string) || is(T == ProcessPipes) || is(T == JSONValue))
T execute(T = string)(string[] args, bool printCommand = true, bool returnErr = false, Redirect redirect = Redirect.all) if (is(T == string) || is(T == ProcessPipes) || is(T == JSONValue))
{
import std.exception : enforce;
import std.format : format;
import std.process : pipeShell, wait, Redirect, escapeShellCommand;
import std.process : pipeShell, wait, escapeShellCommand;
import std.logger : tracef, errorf, infof;
import std.array : join;
import std.algorithm : map;
import std.algorithm : map, canFind;
import std.conv : to;

auto cmd = args.map!escapeShellCommand.join(" ");
auto cmd = args.map!(x => x.canFind("*") ? x : x.escapeShellCommand()).join(" ");

if (printCommand)
{
infof("\n$ `%s`", cmd.bold);
}
auto res = pipeShell(cmd, Redirect.all);
auto res = pipeShell(cmd, redirect);
static if (is(T == ProcessPipes))
{
return res;
Expand Down