Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating and running the VM via quickemu #26

Merged
merged 9 commits into from
Oct 9, 2023
114 changes: 114 additions & 0 deletions scripts/install_quickemu
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/usr/bin/env python3

import platform
import os
import shutil
import sys


def clone_repo():
print("📦 Cloning quickemu...")

print("> git clone --filter=blob:none https://github.com/quickemu-project/quickemu /tmp/quickemu")
os.system("git clone --filter=blob:none https://github.com/quickemu-project/quickemu /tmp/quickemu")

print("> mkdir -p ~/.local/bin")
os.system("mkdir -p ~/.local/bin")

print("> mv /tmp/quickemu/quickemu ~/.local/bin")
os.system("mv /tmp/quickemu/quickemu ~/.local/bin")

print("> mv /tmp/quickemu/macrecovery ~/.local/bin")
os.system("mv /tmp/quickemu/macrecovery ~/.local/bin")

print("> mv /tmp/quickemu/quickget ~/.local/bin")
os.system("mv /tmp/quickemu/quickget ~/.local/bin")

print("> mv /tmp/quickemu/windowskey ~/.local/bin")
oskardotglobal marked this conversation as resolved.
Show resolved Hide resolved
os.system("mv /tmp/quickemu/windowskey ~/.local/bin")

print("> rm -rf /tmp/quickemu")
os.system("rm -rf /tmp/quickemu")

print("Installation complete.")
print("⚠️ Make sure ~/.local/bin is in your PATH.")


def install_fedora():
oskardotglobal marked this conversation as resolved.
Show resolved Hide resolved
print("📦 Installing dependencies...")

cmd = "sudo dnf install qemu bash coreutils edk2-tools grep jq lsb procps python3 genisoimage usbutils util-linux " \
"sed spice-gtk-tools swtpm wget xdg-user-dirs xrandr unzip socat -y"
print("> " + cmd)
os.system(cmd)

clone_repo()

sys.exit(0)


def install_deb():
print("📦 Installing dependencies...")

print("> sudo apt update")
os.system("sudo apt update")

cmd = "sudo apt install qemu bash coreutils ovmf grep jq lsb-base procps python3 genisoimage usbutils util-linux " \
"sed spice-client-gtk libtss2-tcti-swtpm0 wget xdg-user-dirs zsync unzip socat -y"
print("> " + cmd)
os.system(cmd)

clone_repo()

sys.exit(0)


def install_ubuntu():
print("⚠️ Adding ppa...")

print("> sudo apt-add-repository ppa:flexiondotorg/quickemu")
os.system("sudo apt-add-repository ppa:flexiondotorg/quickemu")

print("> sudo apt update")
os.system("sudo apt update")

print("> sudo apt install quickemu -y")
os.system("sudo apt install quickemu -y")

sys.exit(0)


if __name__ == "__main__":
print("⚠️ This script requires elevated privileges (sudo). You will be asked for your password.")

os_release = platform.freedesktop_os_release()

distro_id = os_release.get("ID_LIKE")
distro_id_like = os_release.get("ID")

if not distro_id and not distro_id_like:
print("❌ Couldn't fetch distro, is os-release installed?")

if distro_id == "ubuntu" \
or distro_id_like == "ubuntu":
install_ubuntu()
elif distro_id == "debian" \
or distro_id_like == "debian" \
or shutil.which("apt"):
install_deb()
elif distro_id == "fedora" \
or distro_id_like == "fedora" \
or shutil.which("dnf"):
install_fedora()
else:
if distro_id:
print("❌ Unsupported distro: ", distro_id)
elif distro_id_like:
print("❌ Unsupported distro: ", distro_id_like)
else:
print("❌ Unsupported distro. Couldn't fetch data from os-release and couldn't find dnf or apt on PATH.")

sys.exit(1)

print("❌ Unsupported platform.")
sys.exit(1)
41 changes: 39 additions & 2 deletions winapps-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use clap::Command;
use winapps::RemoteClient;
use winapps::freerdp::freerdp_back::Freerdp;
use winapps::quickemu::{create_vm, kill_vm, start_vm};
use winapps::RemoteClient;

fn cli() -> Command {
Command::new("winapps-cli")
Expand All @@ -10,13 +11,23 @@ fn cli() -> Command {
.allow_external_subcommands(true)
.subcommand(Command::new("check").about("Checks remote connection"))
.subcommand(Command::new("connect").about("Connects to remote"))
.subcommand(
Command::new("vm")
.about("Manage a windows 10 vm using quickemu")
.subcommand_required(true)
.arg_required_else_help(true)
.allow_external_subcommands(true)
.subcommand(Command::new("create").about("Create a windows 10 vm using quickget"))
.subcommand(Command::new("start").about("Start the vm"))
.subcommand(Command::new("kill").about("Kill the running VM")),
)
}

fn main() {
let cli = cli();
let matches = cli.clone().get_matches();

let client: &dyn RemoteClient = &Freerdp{};
let client: &dyn RemoteClient = &Freerdp {};

match matches.subcommand() {
Some(("check", _)) => {
Expand All @@ -31,6 +42,32 @@ fn main() {
let config = winapps::load_config(None);
client.run_app(config, "explorer");
}

Some(("vm", command)) => {
match command.subcommand() {
Some(("create", _)) => {
println!("Creating windows 10 vm..");
create_vm();
}
Some(("start", _)) => {
println!("Starting vm..");
start_vm();
}

Some(("kill", _)) => {
println!("Killing vm..");
kill_vm();
}

Some((_, _)) => {
cli.about("Command not found, try existing ones!")
.print_help()
.expect("Couldn't print help");
}
_ => unreachable!(),
};
}

Some((_, _)) => {
cli.about("Command not found, try existing ones!")
.print_help()
Expand Down
1 change: 1 addition & 0 deletions winapps/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ edition = "2021"

[dependencies]
derive-new = "0.5.9"
home = "0.5.5"
serde = { version = "1.0.171", features = ["derive"] }
toml = "0.7.6"
11 changes: 6 additions & 5 deletions winapps/src/freerdp.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
pub mod freerdp_back {
use std::process::{Command, Stdio};

use crate::{RemoteClient, Config};
use crate::{Config, RemoteClient};

pub struct Freerdp {}

impl RemoteClient for Freerdp {
fn check_depends(&self, _config: Config) {

let mut xfreerdp = Command::new("xfreerdp");
xfreerdp.stdout(Stdio::null());
xfreerdp.args(["-h"]);
xfreerdp.spawn().expect("Freerdp execution failed! It needs to be installed!");
xfreerdp
.spawn()
.expect("Freerdp execution failed! It needs to be installed!");
println!("Freerdp found!");

println!("Checks success!");
}

fn run_app(&self, config: Config, _app: &str) {
fn run_app(&self, _config: Config, _app: &str) {
todo!()
}
}
Expand Down
2 changes: 2 additions & 0 deletions winapps/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub mod quickemu;

use derive_new::new;
use serde::{Deserialize, Serialize};
use std::io::Write;
Expand Down
105 changes: 105 additions & 0 deletions winapps/src/quickemu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use home::home_dir;
use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::exit;
use std::process::Command;

pub fn get_data_dir() -> PathBuf {
let home = home_dir().expect("Could not find the home path!");

let data_dir = match env::var("XDG_DATA_HOME") {
Ok(dir) => PathBuf::from(dir).join("winapps"),
Err(_) => {
println!("Couldn't read XDG_DATA_HOME, falling back to ~/.local/share");
home.join(".local/share/winapps")
}
};

if !data_dir.exists() {
let dir = data_dir.clone();
println!(
"Data directory {:?} does not exist! Creating...",
dir.to_str()
);
std::fs::create_dir_all(dir).expect("Failed to create directory");
}

if !data_dir.is_dir() {
panic!("Data directory {:?} is not a directory!", data_dir.to_str());
}

data_dir
}

pub fn create_vm() {
let data_dir = get_data_dir();

let output = match Command::new("quickget")
.current_dir(data_dir)
.arg("windows")
.arg("10")
.output()
{
Ok(o) => o,
Err(e) => {
println!("Failed to execute quickget: {}", e);
println!("Please make sure quickget is installed and in your PATH");
exit(1);
}
};

println!("{}", String::from_utf8_lossy(&output.stdout));
}

pub fn start_vm() {
let data_dir = get_data_dir();

let command = match Command::new("quickemu")
.current_dir(data_dir)
.args(["--vm", "windows-10-22H2.conf", "--display", "none"])
oskardotglobal marked this conversation as resolved.
Show resolved Hide resolved
.spawn()
{
Ok(c) => c,
Err(e) => {
println!("Failed to execute quickemu: {}", e);
println!("Please make sure quickemu is installed and in your PATH");
exit(1);
}
};

let output = match command.wait_with_output() {
Ok(o) => o,
Err(e) => {
println!("Failed to gather output from quickemu: {}", e);
println!("Please make sure quickemu is installed and in your PATH");
exit(1);
}
};

println!("{}", String::from_utf8_lossy(&output.stdout));
}

pub fn kill_vm() {
let data_dir = get_data_dir();

match fs::read_to_string(data_dir.join("windows-10/windows-10-22H2.pid")) {
Ok(pid) => {
let pid = pid.trim();

println!("Killing VM with PID {}", pid);

match Command::new("kill").arg(pid).spawn() {
Ok(_) => (),
Err(e) => {
println!("Failed to kill VM: {}", e);
exit(1);
}
}
}
Err(e) => {
println!("Failed to read PID file: {}", e);
exit(1);
}
}
}