cli login works and hello-world spacetime module
This commit is contained in:
@@ -18,10 +18,11 @@ reqwest = { version = "0.13.2", features = ["blocking", "json"] }
|
||||
serde = "1.0.228"
|
||||
serde_json = "1.0.149"
|
||||
rusqlite = { version = "0.31", features = ["bundled"], optional = true }
|
||||
dioxus = { version = "0.7.1", features = ["router", "fullstack", "web", "desktop", "mobile", "server", "ssr"], optional = true }
|
||||
|
||||
[features]
|
||||
default = ["target-os"]
|
||||
target-os = [ "clap", "mize/target-os", "rustyscript", "rusqlite" ]
|
||||
target-os = [ "clap", "mize/target-os", "rustyscript", "rusqlite", "dioxus" ]
|
||||
target-wasm = [ "mize/target-wasm" ]
|
||||
clap = ["dep:clap"]
|
||||
|
||||
|
||||
9
packages/marts/c2vi/dashboard.rs
Normal file
9
packages/marts/c2vi/dashboard.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
use dioxus::prelude::*;
|
||||
|
||||
pub fn main() -> Element {
|
||||
rsx! {
|
||||
div {
|
||||
h1 { "my dashbaord" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ use mize::{mize_err, mize_part, Mize, MizeError, MizePart, MizeResult};
|
||||
use crate::cli::CliPart;
|
||||
use crate::habitica::Habitica;
|
||||
|
||||
mod dashboard;
|
||||
|
||||
#[mize_part]
|
||||
#[derive(Default)]
|
||||
pub struct C2vi {
|
||||
@@ -40,7 +42,9 @@ impl C2vi {
|
||||
}
|
||||
|
||||
pub fn c2vi(mize: &mut Mize) -> MizeResult<()> {
|
||||
let storage_path = mize.get_config("c2vi.local_storage_path")?.to_string();
|
||||
//let storage_path = mize.get_config("c2vi.local_storage_path")?.as_
|
||||
let storage_path = "/home/me/work/app-data/ppc";
|
||||
println!("storage_path: {}", storage_path);
|
||||
let db_path = std::path::PathBuf::from(&storage_path).join("data.db");
|
||||
let conn = Connection::open(&db_path)
|
||||
.map_err(|e| mize_err!("Failed to open C2vi database at {:?}: {}", db_path, e))?;
|
||||
@@ -84,6 +88,10 @@ fn setup_tables(conn: &Connection) -> MizeResult<()> {
|
||||
}
|
||||
|
||||
fn register_subcommands(cli: &mut CliPart) {
|
||||
cli.subcommand(
|
||||
Command::new("c2vi-dash").about("Run the c2vi dashboard gui"),
|
||||
|_matches, mut mize| Ok(dioxus::launch(dashboard::main)),
|
||||
);
|
||||
cli.subcommand(
|
||||
Command::new("bed").about("Command to run when c2vi goes to bed"),
|
||||
|_matches, mut mize| {
|
||||
@@ -184,10 +192,7 @@ fn register_subcommands(cli: &mut CliPart) {
|
||||
.map_err(|e| mize_err!("DB error: {}", e))?;
|
||||
let rows = stmt
|
||||
.query_map([], |row| {
|
||||
Ok((
|
||||
row.get::<_, String>(0)?,
|
||||
row.get::<_, String>(1)?,
|
||||
))
|
||||
Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?))
|
||||
})
|
||||
.map_err(|e| mize_err!("DB error: {}", e))?;
|
||||
for row in rows {
|
||||
@@ -206,15 +211,17 @@ fn register_subcommands(cli: &mut CliPart) {
|
||||
|matches, mut mize| {
|
||||
let id = matches.get_one::<String>("id").unwrap();
|
||||
let mut hab = mize.get_part_native::<Habitica>("habitica")?;
|
||||
let data = hab.api_request(
|
||||
reqwest::Method::GET,
|
||||
format!("tasks/{}", id),
|
||||
json!({}),
|
||||
)?;
|
||||
let data = hab.api_request(reqwest::Method::GET, format!("tasks/{}", id), json!({}))?;
|
||||
if let Some(history) = data.get("history") {
|
||||
println!("{}", serde_json::to_string_pretty(history).unwrap_or_default());
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::to_string_pretty(history).unwrap_or_default()
|
||||
);
|
||||
} else {
|
||||
println!("{}", serde_json::to_string_pretty(&data).unwrap_or_default());
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::to_string_pretty(&data).unwrap_or_default()
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
@@ -250,9 +257,7 @@ fn get_or_create_log(conn: &Connection, date: &str) -> MizeResult<Value> {
|
||||
let mut stmt = conn
|
||||
.prepare("SELECT data FROM habitica_log WHERE date = ?1")
|
||||
.map_err(|e| mize_err!("DB error: {}", e))?;
|
||||
let result: Option<String> = stmt
|
||||
.query_row(params![date], |row| row.get(0))
|
||||
.ok();
|
||||
let result: Option<String> = stmt.query_row(params![date], |row| row.get(0)).ok();
|
||||
match result {
|
||||
Some(data_str) => {
|
||||
serde_json::from_str(&data_str).map_err(|e| mize_err!("JSON parse error: {}", e))
|
||||
@@ -394,7 +399,10 @@ fn save_habitica_logs(mize: &mut Mize) -> MizeResult<()> {
|
||||
if save_for_yesterday {
|
||||
let existing_todos = data["todos_done"].as_array().unwrap();
|
||||
let todo_id = todo["id"].as_str().unwrap_or("");
|
||||
if existing_todos.iter().any(|t| t["id"].as_str() == Some(todo_id)) {
|
||||
if existing_todos
|
||||
.iter()
|
||||
.any(|t| t["id"].as_str() == Some(todo_id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -419,10 +427,7 @@ fn save_habitica_logs(mize: &mut Mize) -> MizeResult<()> {
|
||||
// If saving for yesterday but todo was completed today, also record it
|
||||
if save_for_yesterday && date_completed == today_str {
|
||||
println!("todo-done: {}", todo["text"].as_str().unwrap_or(""));
|
||||
data["todos_done"]
|
||||
.as_array_mut()
|
||||
.unwrap()
|
||||
.push(todo_entry);
|
||||
data["todos_done"].as_array_mut().unwrap().push(todo_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -441,7 +446,9 @@ fn skip_habitica_todo(mize: &mut Mize, num: usize) -> MizeResult<()> {
|
||||
hab.get_tasks("todos")?
|
||||
};
|
||||
|
||||
let arr = todos.as_array().ok_or_else(|| mize_err!("Expected array of todos"))?;
|
||||
let arr = todos
|
||||
.as_array()
|
||||
.ok_or_else(|| mize_err!("Expected array of todos"))?;
|
||||
|
||||
// Delete and log each skipped todo
|
||||
for i in 0..num {
|
||||
@@ -517,10 +524,8 @@ se 21:40
|
||||
read
|
||||
bed 22:10";
|
||||
|
||||
let tmp_file = std::env::temp_dir().join(format!(
|
||||
"habitica-tasks-{}.md",
|
||||
Utc::now().timestamp()
|
||||
));
|
||||
let tmp_file =
|
||||
std::env::temp_dir().join(format!("habitica-tasks-{}.md", Utc::now().timestamp()));
|
||||
std::fs::write(&tmp_file, initial_content)
|
||||
.map_err(|e| mize_err!("Failed to write temp file: {}", e))?;
|
||||
|
||||
@@ -531,8 +536,8 @@ bed 22:10";
|
||||
.map_err(|e| mize_err!("Failed to run nvim: {}", e))?;
|
||||
|
||||
// Read back and parse
|
||||
let list_str =
|
||||
std::fs::read_to_string(&tmp_file).map_err(|e| mize_err!("Failed to read temp file: {}", e))?;
|
||||
let list_str = std::fs::read_to_string(&tmp_file)
|
||||
.map_err(|e| mize_err!("Failed to read temp file: {}", e))?;
|
||||
let _ = std::fs::remove_file(&tmp_file);
|
||||
|
||||
let tasks: Vec<&str> = list_str
|
||||
@@ -577,17 +582,18 @@ fn dump_habitica_logs(mize: &mut Mize) -> MizeResult<()> {
|
||||
.map_err(|e| mize_err!("DB error: {}", e))?;
|
||||
let rows = stmt
|
||||
.query_map([], |row| {
|
||||
Ok((
|
||||
row.get::<_, String>(0)?,
|
||||
row.get::<_, String>(1)?,
|
||||
))
|
||||
Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?))
|
||||
})
|
||||
.map_err(|e| mize_err!("DB error: {}", e))?;
|
||||
for row in rows {
|
||||
let (date, data_str) = row.map_err(|e| mize_err!("DB error: {}", e))?;
|
||||
let data: Value =
|
||||
serde_json::from_str(&data_str).unwrap_or(json!({"parse_error": data_str}));
|
||||
println!("{}: {}", date, serde_json::to_string_pretty(&data).unwrap_or_default());
|
||||
println!(
|
||||
"{}: {}",
|
||||
date,
|
||||
serde_json::to_string_pretty(&data).unwrap_or_default()
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
"name": "@ppc/marts",
|
||||
"imports": {},
|
||||
"exports": {
|
||||
".": "./index.ts",
|
||||
"stub_deno": "./js/stub_deno.ts"
|
||||
".": "./index.ts"
|
||||
},
|
||||
"tasks": {
|
||||
"build": "deno bundle -o ./deno_dist/habitica.js ./habitica.ts && deno -A ./esbuild.config.mjs"
|
||||
}
|
||||
"tasks": {}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
export { task_obsidian_otask_parse } from "./task/obsidian-otask-parse";
|
||||
export { c2vi_obsidian_canvas_patch } from "./c2vi/obsidian-canvas-patch";
|
||||
export * from "./task/obsidian-otask-parse";
|
||||
export * from "./c2vi/obsidian-canvas-patch";
|
||||
|
||||
export * from "./js/stub_deno";
|
||||
|
||||
@@ -16,7 +16,7 @@ pub mod c2vi;
|
||||
#[cfg(feature = "target-os")]
|
||||
pub use c2vi::*;
|
||||
|
||||
#[cfg(feature = "target-os")]
|
||||
pub mod js;
|
||||
#[cfg(feature = "target-os")]
|
||||
pub use js::*;
|
||||
//#[cfg(feature = "target-os")]
|
||||
//pub mod js;
|
||||
//#[cfg(feature = "target-os")]
|
||||
//pub use js::*;
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
{
|
||||
"name": "marts",
|
||||
"name": "@ppc/marts",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"packageManager": "pnpm@10.15.1",
|
||||
"dependencies": {
|
||||
"@flowershow/remark-wiki-link": "^3.4.0",
|
||||
"builtin-modules": "^5.0.0",
|
||||
"esbuild": "^0.27.3",
|
||||
"mdast": "^3.0.0",
|
||||
"obsidian": "^1.12.2",
|
||||
"obsidian": "^1.12.3",
|
||||
"remark-frontmatter": "^5.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"remark-parse": "^11.0.0",
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { id, i, init, InstaQLEntity } from "@instantdb/react";
|
||||
import remarkParse from "remark-parse";
|
||||
import remarkStringify from "remark-stringify";
|
||||
import { unified } from "unified";
|
||||
@@ -7,6 +6,7 @@ import { Root, Content, Heading, List, ListItem, Text } from "mdast";
|
||||
import remarkFrontmatter from "remark-frontmatter";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import wikiLinkPlugin from "@flowershow/remark-wiki-link";
|
||||
import { TFile } from "obsidian";
|
||||
|
||||
const OTASK_PROP_NAMES = ["short", "outcome", "priority"];
|
||||
const ACTION_PROP_NAMES = [];
|
||||
@@ -77,7 +77,7 @@ async function full_parse() {
|
||||
render_sub0_file(OTASK_LIST);
|
||||
}
|
||||
|
||||
let OTASK_PARSE_QUEUE = [];
|
||||
let OTASK_PARSE_QUEUE: any = [];
|
||||
let OTASK_LIST = [];
|
||||
let DBG = false;
|
||||
|
||||
@@ -201,130 +201,37 @@ async function replaceHeading(
|
||||
}
|
||||
|
||||
async function otasks_from_list_item(listItem, otask_path, priority = 0) {
|
||||
// the main otask this listItem is about
|
||||
let otask = {
|
||||
description: [],
|
||||
actions: [],
|
||||
path: [],
|
||||
priority,
|
||||
};
|
||||
dbg("SystemC2: otasks_from_list_item", listItem, otask_path);
|
||||
try {
|
||||
// the main otask this listItem is about
|
||||
let otask = {
|
||||
description: [],
|
||||
actions: [],
|
||||
path: [],
|
||||
priority,
|
||||
};
|
||||
dbg("SystemC2: otasks_from_list_item", listItem, otask_path);
|
||||
|
||||
if (!listItem.children[0].type === "paragraph") {
|
||||
dbg(
|
||||
"listItem[0] of a otask item is not a paragraph... the otask:",
|
||||
listItem,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
let longName = nodeToString(listItem.children[0]);
|
||||
|
||||
dbg("longName:", longName);
|
||||
|
||||
// check for [[anotherotask]], call otasks_from_file, return those
|
||||
const match = longName.match(/\[\[([^\]]+)\]\]/);
|
||||
if (match) {
|
||||
const file = app.metadataCache.getFirstLinkpathDest(match[1], "");
|
||||
if (file) {
|
||||
const metadata = app.metadataCache.getFileCache(file);
|
||||
|
||||
if (metadata?.frontmatter?.tags?.includes("t/otask")) {
|
||||
queue_otasks_from_file(file, otask_path);
|
||||
return null;
|
||||
} else {
|
||||
dbg(
|
||||
"SystemC2: listItem with Link to '",
|
||||
match[1],
|
||||
"', which is not an otask",
|
||||
longName,
|
||||
);
|
||||
}
|
||||
if (!listItem.children[0].type === "paragraph") {
|
||||
dbg(
|
||||
"listItem[0] of a otask item is not a paragraph... the otask:",
|
||||
listItem,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
let longName = nodeToString(listItem.children[0]);
|
||||
|
||||
//check for [x] and remove from name
|
||||
if (longName.startsWith("[ ") || longName.startsWith("[x")) {
|
||||
longName = longName.slice(4);
|
||||
}
|
||||
dbg("longName:", longName);
|
||||
|
||||
//check for "ot:" and remove from name
|
||||
if (longName.startsWith("ot:")) {
|
||||
longName = longName.slice(4);
|
||||
}
|
||||
|
||||
otask.longName = longName;
|
||||
otask.short = longName;
|
||||
otask.path = otask_path;
|
||||
let new_otask_path = [...otask_path, otask.short];
|
||||
|
||||
// go through sub list items
|
||||
// - if it's a prop for the otask... handle that
|
||||
// - if it's an "ac:" handle that
|
||||
// - if it's "ot: " handle as another otask -> recursive call
|
||||
// - if it's "[ ]" handle as another otask -> recursive call
|
||||
// - if it's a link to a otask file... handle as another otask -> call otasks_from_file()
|
||||
// - else add it as description item list to otask
|
||||
if (!listItem.children || listItem.children.length < 2) {
|
||||
return otask;
|
||||
}
|
||||
|
||||
// add content as text to otask
|
||||
if (otask.longName == "hosting updates") {
|
||||
console.log("listItem... ", listItem.children[1]);
|
||||
let hii = REMARK.stringify(listItem.children[1]);
|
||||
console.log("text...", hii);
|
||||
}
|
||||
let content_text = REMARK.stringify(listItem.children[1]);
|
||||
otask.content = content_text;
|
||||
|
||||
for (const subListItem of listItem.children[1].children) {
|
||||
let text = nodeToString(subListItem.children[0]);
|
||||
|
||||
// check prop
|
||||
if (check_otask_prop_from_list_item(subListItem, otask)) {
|
||||
new_otask_path = [...otask_path, otask.short]; // have to redo it here, in case short changed from aprop
|
||||
continue; // don't do any other processing on this sub-listItem
|
||||
}
|
||||
|
||||
// remove "[ ]"
|
||||
if (text.startsWith("[ ") || text.startsWith("[x")) {
|
||||
text = text.slice(4);
|
||||
}
|
||||
|
||||
// check ac
|
||||
if (text.startsWith("ac:")) {
|
||||
otask.actions = [
|
||||
...otask.actions,
|
||||
action_from_list_item(subListItem, new_otask_path, otask.priority),
|
||||
];
|
||||
|
||||
continue; // don't do any other processing on this sub-listItem
|
||||
}
|
||||
|
||||
// check ot
|
||||
if (text.startsWith("ot:")) {
|
||||
queue_otasks_from_list_item(subListItem, new_otask_path, otask.priority);
|
||||
|
||||
continue; // don't do any other processing on this sub-listItem
|
||||
}
|
||||
|
||||
// check [ ]
|
||||
if (text.startsWith("[ ] ") || text.startsWith("[x] ")) {
|
||||
queue_otasks_from_list_item(subListItem, new_otask_path, otask.priority);
|
||||
|
||||
continue; // don't do any other processing on this sub-listItem
|
||||
}
|
||||
|
||||
// check link to otask file
|
||||
const match = text.match(/\[\[([^\]]+)\]\]/);
|
||||
// check for [[anotherotask]], call otasks_from_file, return those
|
||||
const match = longName.match(/\[\[([^\]]+)\]\]/);
|
||||
if (match) {
|
||||
const file = app.metadataCache.getFirstLinkpathDest(match[1], "");
|
||||
if (file) {
|
||||
const metadata = app.metadataCache.getFileCache(file);
|
||||
|
||||
if (metadata?.frontmatter?.tags?.includes("t/otask")) {
|
||||
queue_otasks_from_file(file, new_otask_path, otask.priority);
|
||||
continue;
|
||||
queue_otasks_from_file(file, otask_path);
|
||||
return null;
|
||||
} else {
|
||||
dbg(
|
||||
"SystemC2: listItem with Link to '",
|
||||
@@ -333,83 +240,192 @@ async function otasks_from_list_item(listItem, otask_path, priority = 0) {
|
||||
longName,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//check for [x] and remove from name
|
||||
if (longName.startsWith("[ ") || longName.startsWith("[x")) {
|
||||
longName = longName.slice(4);
|
||||
}
|
||||
|
||||
//check for "ot:" and remove from name
|
||||
if (longName.startsWith("ot:")) {
|
||||
longName = longName.slice(4);
|
||||
}
|
||||
|
||||
otask.longName = longName;
|
||||
otask.short = longName;
|
||||
otask.path = otask_path;
|
||||
let new_otask_path = [...otask_path, otask.short];
|
||||
|
||||
// go through sub list items
|
||||
// - if it's a prop for the otask... handle that
|
||||
// - if it's an "ac:" handle that
|
||||
// - if it's "ot: " handle as another otask -> recursive call
|
||||
// - if it's "[ ]" handle as another otask -> recursive call
|
||||
// - if it's a link to a otask file... handle as another otask -> call otasks_from_file()
|
||||
// - else add it as description item list to otask
|
||||
if (!listItem.children || listItem.children.length < 2) {
|
||||
return otask;
|
||||
}
|
||||
|
||||
// add content as text to otask
|
||||
if (otask.longName == "hosting updates") {
|
||||
console.log("listItem... ", listItem.children[1]);
|
||||
let hii = REMARK.stringify(listItem.children[1]);
|
||||
console.log("text...", hii);
|
||||
}
|
||||
let content_text = REMARK.stringify(listItem.children[1]);
|
||||
otask.content = content_text;
|
||||
|
||||
for (const subListItem of listItem.children[1].children) {
|
||||
let text = nodeToString(subListItem.children[0]);
|
||||
|
||||
// check prop
|
||||
if (check_otask_prop_from_list_item(subListItem, otask)) {
|
||||
new_otask_path = [...otask_path, otask.short]; // have to redo it here, in case short changed from aprop
|
||||
continue; // don't do any other processing on this sub-listItem
|
||||
}
|
||||
|
||||
// remove "[ ]"
|
||||
if (text.startsWith("[ ") || text.startsWith("[x")) {
|
||||
text = text.slice(4);
|
||||
}
|
||||
|
||||
// check ac
|
||||
if (text.startsWith("ac:")) {
|
||||
otask.actions = [
|
||||
...otask.actions,
|
||||
action_from_list_item(subListItem, new_otask_path, otask.priority),
|
||||
];
|
||||
|
||||
continue; // don't do any other processing on this sub-listItem
|
||||
}
|
||||
|
||||
// check ot
|
||||
if (text.startsWith("ot:")) {
|
||||
queue_otasks_from_list_item(
|
||||
subListItem,
|
||||
new_otask_path,
|
||||
otask.priority,
|
||||
);
|
||||
|
||||
continue; // don't do any other processing on this sub-listItem
|
||||
}
|
||||
|
||||
// check [ ]
|
||||
if (text.startsWith("[ ] ") || text.startsWith("[x] ")) {
|
||||
queue_otasks_from_list_item(
|
||||
subListItem,
|
||||
new_otask_path,
|
||||
otask.priority,
|
||||
);
|
||||
|
||||
continue; // don't do any other processing on this sub-listItem
|
||||
}
|
||||
|
||||
// check link to otask file
|
||||
const match = text.match(/\[\[([^\]]+)\]\]/);
|
||||
if (match) {
|
||||
const file = app.metadataCache.getFirstLinkpathDest(match[1], "");
|
||||
if (file) {
|
||||
const metadata = app.metadataCache.getFileCache(file);
|
||||
|
||||
if (metadata?.frontmatter?.tags?.includes("t/otask")) {
|
||||
queue_otasks_from_file(file, new_otask_path, otask.priority);
|
||||
continue;
|
||||
} else {
|
||||
dbg(
|
||||
"SystemC2: listItem with Link to '",
|
||||
match[1],
|
||||
"', which is not an otask",
|
||||
longName,
|
||||
);
|
||||
}
|
||||
|
||||
continue; // don't do any other processing on this sub-listItem
|
||||
}
|
||||
}
|
||||
|
||||
// add as description
|
||||
const desc = REMARK.stringify(subListItem);
|
||||
otask.description.push(desc);
|
||||
}
|
||||
|
||||
return otask;
|
||||
} catch (error) {
|
||||
console.log("failed to parse list item:", listItem);
|
||||
}
|
||||
}
|
||||
|
||||
async function otasks_from_file(file: TFile, otask_path, priority = 0) {
|
||||
try {
|
||||
dbg("SystemC2: otasks_from_file", file, otask_path);
|
||||
|
||||
// the main otask this file is about
|
||||
let otask = {
|
||||
description: [],
|
||||
actions: [],
|
||||
path: [],
|
||||
priority,
|
||||
is_file: true,
|
||||
};
|
||||
|
||||
otask.longName = file.basename;
|
||||
otask.short = otask.longName;
|
||||
otask.path = otask_path;
|
||||
let new_otask_path = [...otask_path, otask.short];
|
||||
|
||||
const content = await app.vault.read(file);
|
||||
|
||||
// parse listItems at the top... for props
|
||||
const topListItems = getListItemsBeforeFirstHeading(content);
|
||||
for (const topListItem of topListItems) {
|
||||
const text = nodeToString(topListItem);
|
||||
|
||||
// check for prop
|
||||
if (check_otask_prop_from_list_item(topListItem, otask)) {
|
||||
new_otask_path = [...otask_path, otask.short];
|
||||
continue; // don't do any other processing on this sub-listItem
|
||||
}
|
||||
}
|
||||
|
||||
// add as description
|
||||
const desc = REMARK.stringify(subListItem);
|
||||
otask.description.push(desc);
|
||||
}
|
||||
// parse all the sub sections
|
||||
const SUB_COUNT = 10;
|
||||
for (let sub_number = 0; sub_number < SUB_COUNT; sub_number++) {
|
||||
let listItems = await getListUnderHeading(content, "sub" + sub_number);
|
||||
|
||||
return otask;
|
||||
}
|
||||
|
||||
async function otasks_from_file(file: TFile, otask_path, priority = 0) {
|
||||
dbg("SystemC2: otasks_from_file", file, otask_path);
|
||||
|
||||
// the main otask this file is about
|
||||
let otask = {
|
||||
description: [],
|
||||
actions: [],
|
||||
path: [],
|
||||
priority,
|
||||
is_file: true,
|
||||
};
|
||||
|
||||
otask.longName = file.basename;
|
||||
otask.short = otask.longName;
|
||||
otask.path = otask_path;
|
||||
let new_otask_path = [...otask_path, otask.short];
|
||||
|
||||
const content = await app.vault.read(file);
|
||||
|
||||
// parse listItems at the top... for props
|
||||
const topListItems = getListItemsBeforeFirstHeading(content);
|
||||
for (const topListItem of topListItems) {
|
||||
const text = nodeToString(topListItem);
|
||||
|
||||
// check for prop
|
||||
if (check_otask_prop_from_list_item(topListItem, otask)) {
|
||||
new_otask_path = [...otask_path, otask.short];
|
||||
continue; // don't do any other processing on this sub-listItem
|
||||
}
|
||||
}
|
||||
|
||||
// parse all the sub sections
|
||||
const SUB_COUNT = 10;
|
||||
for (let sub_number = 0; sub_number < SUB_COUNT; sub_number++) {
|
||||
let listItems = await getListUnderHeading(content, "sub" + sub_number);
|
||||
|
||||
// "sub" without a number should have priority 5
|
||||
if (sub_number == 5) {
|
||||
listItems = listItems.concat(await getListUnderHeading(content, "sub"));
|
||||
}
|
||||
|
||||
//dbg(`sub section ${sub_number} has items:`, listItems)
|
||||
|
||||
for (const listItem of listItems) {
|
||||
// check if listItem is an action...
|
||||
let text = nodeToString(listItem.children[0]);
|
||||
if (
|
||||
text.startsWith("ac:") ||
|
||||
text.startsWith("[ ] ac:") ||
|
||||
text.startsWith("[x] ac:")
|
||||
) {
|
||||
const action = action_from_list_item(listItem, otask_path);
|
||||
otask.actions.push(action);
|
||||
// "sub" without a number should have priority 5
|
||||
if (sub_number == 5) {
|
||||
listItems = listItems.concat(await getListUnderHeading(content, "sub"));
|
||||
}
|
||||
|
||||
queue_otasks_from_list_item(
|
||||
listItem,
|
||||
new_otask_path,
|
||||
otask.priority + sub_number,
|
||||
);
|
||||
}
|
||||
}
|
||||
//dbg(`sub section ${sub_number} has items:`, listItems)
|
||||
|
||||
return otask;
|
||||
for (const listItem of listItems) {
|
||||
// check if listItem is an action...
|
||||
let text = nodeToString(listItem.children[0]);
|
||||
if (
|
||||
text.startsWith("ac:") ||
|
||||
text.startsWith("[ ] ac:") ||
|
||||
text.startsWith("[x] ac:")
|
||||
) {
|
||||
const action = action_from_list_item(listItem, otask_path);
|
||||
otask.actions.push(action);
|
||||
}
|
||||
|
||||
queue_otasks_from_list_item(
|
||||
listItem,
|
||||
new_otask_path,
|
||||
otask.priority + sub_number,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return otask;
|
||||
} catch (error) {
|
||||
console.log("failed to parse file: ", file.path);
|
||||
}
|
||||
}
|
||||
|
||||
function action_from_list_item(listItem, otask_path) {
|
||||
|
||||
154
packages/mize/flake.lock
generated
154
packages/mize/flake.lock
generated
@@ -1,154 +0,0 @@
|
||||
{
|
||||
"nodes": {
|
||||
"crane": {
|
||||
"locked": {
|
||||
"lastModified": 1769737823,
|
||||
"narHash": "sha256-DrBaNpZ+sJ4stXm+0nBX7zqZT9t9P22zbk6m5YhQxS4=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "b2f45c3830aa96b7456a4c4bc327d04d7a43e1ba",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1770102568,
|
||||
"narHash": "sha256-VYwA9FmakKJ3zLfAd7bdj9xIB9PzfISLoYh6eZl+EuQ=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "592daa37b5a3175c61541329b64d6c1972303bc1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"mize_modules": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1739053120,
|
||||
"narHash": "sha256-It6j1D3c3eO/O0ptHvZ3c9Ynei08DXX5n6DYonW3g+s=",
|
||||
"owner": "c2vi",
|
||||
"repo": "mize-modules",
|
||||
"rev": "3bba470c849f7cbaf7eb7858c26aa1c64fd00b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "c2vi",
|
||||
"repo": "mize-modules",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1770115704,
|
||||
"narHash": "sha256-KHFT9UWOF2yRPlAnSXQJh6uVcgNcWlFqqiAZ7OVlHNc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e6eae2ee2110f3d31110d5c222cd395303343b08",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"crane": "crane",
|
||||
"fenix": "fenix",
|
||||
"flake-utils": "flake-utils",
|
||||
"mize_modules": "mize_modules",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1770026591,
|
||||
"narHash": "sha256-VZlloygYDmozJwbZZkCSNpiPhNdOW/AA0b6LmNBZ3xU=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "74eca73f3b0a41b80228b8e499c7547cc8b2effa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1770088046,
|
||||
"narHash": "sha256-4hfYDnUTvL1qSSZEA4CEThxfz+KlwSFQ30Z9jgDguO0=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "71f9daa4e05e49c434d08627e755495ae222bc34",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@@ -1,224 +0,0 @@
|
||||
{
|
||||
inputs = {
|
||||
# nixpkgs 35.11 still contains rust 1.73
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
|
||||
fenix = {
|
||||
url = "github:nix-community/fenix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
crane = {
|
||||
url = "github:ipetkov/crane";
|
||||
};
|
||||
|
||||
rust-overlay = {
|
||||
url = "github:oxalica/rust-overlay";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
mize_modules = {
|
||||
url = "github:c2vi/mize-modules?submodules=1";
|
||||
flake = false;
|
||||
};
|
||||
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
outputs = { self, flake-utils, nixpkgs, fenix, crane, mize_modules, rust-overlay, ... }@inputs: flake-utils.lib.eachDefaultSystem (system:
|
||||
|
||||
############################## LET BINDINGS ##############################
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
wasmToolchain = fenix.packages.${system}.combine [
|
||||
fenix.packages.${system}.targets.wasm32-unknown-unknown.stable.toolchain
|
||||
fenix.packages.${system}.stable.toolchain
|
||||
];
|
||||
wasmCrane = (crane.mkLib pkgs).overrideToolchain wasmToolchain;
|
||||
|
||||
osToolchain = fenix.packages.${system}.nightly.toolchain;
|
||||
|
||||
osCrane = (crane.mkLib pkgs).overrideToolchain osToolchain;
|
||||
|
||||
#winToolchain = fenix.packages.${system}.combine [
|
||||
#fenix.packages.${system}.targets.x86_64-pc-windows-gnu.latest.toolchain
|
||||
#fenix.packages.${system}.latest.toolchain
|
||||
#];
|
||||
winToolchain = with fenix.packages.${system};
|
||||
combine [
|
||||
minimal.rustc
|
||||
minimal.cargo
|
||||
targets.x86_64-pc-windows-gnu.latest.rust-std
|
||||
];
|
||||
winCrane = (crane.mkLib pkgs).overrideToolchain winToolchain;
|
||||
|
||||
wasmArtifacts = wasmCrane.buildDepsOnly ({
|
||||
src = self;
|
||||
doCheck = false; # tests does not work in wasm
|
||||
CARGO_BUILD_TARGET = "wasm32-unknown-unknown";
|
||||
cargoExtraArgs = "--features target-wasm --no-default-features";
|
||||
RUSTFLAGS="-C linker=wasm-ld";
|
||||
buildInputs = with pkgs; [ cargo-binutils lld ];
|
||||
});
|
||||
|
||||
defaultMizeConfig = {
|
||||
config = {
|
||||
namespace = "mize.buildtime.ns";
|
||||
module_url = "c2vi.dev";
|
||||
};
|
||||
};
|
||||
|
||||
#systems = [ "aarch64-linux" "x86_64-linux" "x86_64-pc-windows-gnu" "wasm32-unknown-none-unknown" "x86_64-apple-darwin" "aarch64-apple-darwin" ];
|
||||
systems = [ "aarch64-unknown-linux-gnu" "x86_64-unknown-linux-gnu" "x86_64-pc-windows-gnu" "wasm32-unknown-none-unknown" ];
|
||||
|
||||
mizeLib = import ./lib.nix {
|
||||
inherit inputs nixpkgs pkgs self osCrane defaultMizeConfig mize_modules;
|
||||
inherit rust-overlay crane fenix;
|
||||
buildSystem = system;
|
||||
stdenv = pkgs.stdenv;
|
||||
};
|
||||
|
||||
in {
|
||||
############################## PACKAGES ##############################
|
||||
|
||||
packages = rec {
|
||||
|
||||
inherit osCrane;
|
||||
#test = mizeLib.buildMizeForSystem "wasm32-unknown-none-unknown";
|
||||
test = mizeLib.buildMizeForSystem "aarch64-linux";
|
||||
#test = mizeLib.buildMizeForSystem "x86_64-pc-windows-gnu";
|
||||
|
||||
mizeFor = let
|
||||
mizes = map mizeLib.buildMizeForSystem systems;
|
||||
in builtins.listToAttrs ( map ( mize: { name = mize.system.name; value = mize; } ) mizes );
|
||||
|
||||
dist = mizeLib.dist systems;
|
||||
|
||||
random = mizeLib.random systems;
|
||||
|
||||
inherit mizeLib;
|
||||
|
||||
|
||||
#pkgsCross = import nixpkgs { buildSystem = system; crossSystem = { config = "x86_64-pc-windows-gnu"; }; overlays = [ rust-overlay.overlays.default ]; };
|
||||
|
||||
pkgsTest = pkgs;
|
||||
|
||||
#pkgsCross = import nixpkgs { buildSystem = system; crossSystem = { config = "x86_64-w64-windows-mingw"; }; overlays = [ rust-overlay.overlays.default ]; };
|
||||
pkgsCross = import nixpkgs { buildSystem = system; crossSystem = { config = "x86_64-unknown-linux-gnu"; }; overlays = [ rust-overlay.overlays.default ]; };
|
||||
craneLib = (crane.mkLib pkgsCross).overrideToolchain (p: p.rust-bin.stable.latest.default);
|
||||
|
||||
|
||||
one = craneLib.buildPackage {
|
||||
src = "${self}";
|
||||
#cargoExtraArgs = "--bin mize --features target-os";
|
||||
cargoExtraArgs = "--bin mize";
|
||||
doCheck = false; # tests does not work in wasm
|
||||
CARGO_BUILD_TARGET = "x86_64-pc-windows-gnu";
|
||||
MIZE_BUILD_CONFIG = pkgs.writeTextFile {
|
||||
name = "mize-build-config";
|
||||
text = builtins.toJSON (defaultMizeConfig // {
|
||||
mize_version = one.version;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
default = osCrane.buildPackage {
|
||||
src = "${self}";
|
||||
cargoExtraArgs = "--bin mize --features target-os";
|
||||
};
|
||||
|
||||
wasm = wasmCrane.buildPackage {
|
||||
src = "${self}";
|
||||
CARGO_BUILD_TARGET = "wasm32-unknown-unknown";
|
||||
cargoExtraArgs = "--bin mize --features target-wasm ";
|
||||
doCheck = false;
|
||||
};
|
||||
inherit wasmArtifacts;
|
||||
|
||||
# Thanks to:
|
||||
# - https://github.com/dl-solarity/hardhat-diamond-tools/blob/e5b8bc9624fbf89eda83a8ce4f6b6672ea83f550/flake.nix#L103
|
||||
# - https://github.com/ipetkov/crane/issues/362#issuecomment-1683220603
|
||||
npmPackage = wasmCrane.mkCargoDerivation {
|
||||
name = "mize-npm-package";
|
||||
|
||||
# i can't use CARGO_BUILD_TARGET to set the target
|
||||
# because then the cargo install run by wasm-pack tries to build the wasm-bindgen-cli for a wasm target...
|
||||
|
||||
|
||||
src = self;
|
||||
|
||||
cargoArtifacts = wasmArtifacts;
|
||||
doCheck = false;
|
||||
|
||||
buildPhaseCargoCommand = ''
|
||||
echo build hiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
|
||||
mkdir -p $out/pkg
|
||||
|
||||
export HOME=$(mktemp -d fake-homeXXXX)
|
||||
wasm-pack build --out-dir $out/pkg --scope=c2vi -- --no-default-features --features target-wasm
|
||||
'';
|
||||
|
||||
buildInputs = with pkgs; [ wasm-bindgen-cli binaryen wasm-pack wasmToolchain ];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
############################## DEV SHELLS ##############################
|
||||
devShells = {
|
||||
|
||||
modules = mizeLib.moduleShells system;
|
||||
|
||||
modulesCross = pkgs.lib.genAttrs systems (system: mizeLib.moduleShells system);
|
||||
|
||||
one = pkgs.stdenv.mkDerivation {
|
||||
name = "hiiiiiiii";
|
||||
nativeBuildInputs = [
|
||||
(fenix.packages.${system}.combine [
|
||||
fenix.packages.${system}.targets.wasm32-unknown-unknown.latest.toolchain
|
||||
fenix.packages.${system}.latest.toolchain
|
||||
fenix.packages.${system}.latest.rust-src
|
||||
])
|
||||
];
|
||||
};
|
||||
|
||||
win = winCrane.buildPackage {
|
||||
#src = winCrane.cleanCargoSource ./testing;
|
||||
#pname = "testing";
|
||||
src = ./testing;
|
||||
|
||||
strictDeps = true;
|
||||
doCheck = false;
|
||||
|
||||
CARGO_BUILD_TARGET = "x86_64-pc-windows-gnu";
|
||||
|
||||
# fixes issues related to libring
|
||||
TARGET_CC = "${pkgs.pkgsCross.mingwW64.stdenv.cc}/bin/${pkgs.pkgsCross.mingwW64.stdenv.cc.targetPrefix}cc";
|
||||
|
||||
#fixes issues related to openssl
|
||||
OPENSSL_DIR = "${pkgs.openssl.dev}";
|
||||
OPENSSL_LIB_DIR = "${pkgs.openssl.out}/lib";
|
||||
OPENSSL_INCLUDE_DIR = "${pkgs.openssl.dev}/include/";
|
||||
|
||||
depsBuildBuild = with pkgs; [
|
||||
pkgsCross.mingwW64.stdenv.cc
|
||||
pkgsCross.mingwW64.windows.pthreads
|
||||
];
|
||||
shellHook = ''
|
||||
export MIZE_CONFIG_FILE=${self}/test-config.toml
|
||||
'';
|
||||
MIZE_BUILD_CONFIG = pkgs.writeTextFile {
|
||||
name = "vic-build-config";
|
||||
text = builtins.toJSON defaultMizeConfig;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
default = (mizeLib.buildMizeForSystem system).modules.mize.devShell;
|
||||
};
|
||||
|
||||
}) // {
|
||||
|
||||
############################## SOME GLOBAL OUTPUTS ##############################
|
||||
inherit inputs self;
|
||||
rustPkgs = import nixpkgs { overlays = [rust-overlay.overlays.default]; system = "x86_64-linux"; };
|
||||
};
|
||||
}
|
||||
@@ -1,445 +0,0 @@
|
||||
{ pkgs
|
||||
, osCrane
|
||||
, self
|
||||
, defaultMizeConfig
|
||||
, mize_modules
|
||||
, buildSystem
|
||||
, nixpkgs
|
||||
, rust-overlay
|
||||
, crane
|
||||
, fenix
|
||||
, stdenv
|
||||
, lib ? pkgs.lib
|
||||
, ...
|
||||
}:
|
||||
rec {
|
||||
|
||||
|
||||
|
||||
|
||||
getCrossSystem = system: let
|
||||
hostSystem = (if builtins.isString system then (pkgs.lib.systems.parse.mkSystemFromString system) else system)
|
||||
// rec {
|
||||
name = if hostSystem.vendor != "unknown"
|
||||
then "${hostSystem.cpu.name}-${hostSystem.kernel.name}-${hostSystem.abi.name}"
|
||||
else "${hostSystem.cpu.name}-${hostSystem.vendor.name}-${hostSystem.kernel.name}-${hostSystem.abi.name}";
|
||||
nameFull = "${hostSystem.cpu.name}-${hostSystem.vendor.name}-${hostSystem.kernel.name}-${hostSystem.abi.name}";
|
||||
nameRust = nameFull;
|
||||
config = nameFull;
|
||||
isCross = system != buildSystem;
|
||||
isNative = system == buildSystem;
|
||||
};
|
||||
in hostSystem;
|
||||
|
||||
|
||||
# get a list of all modules
|
||||
# aka folders with a mize.nix in them
|
||||
module_list_drv = path: pkgs.stdenv.mkDerivation {
|
||||
name = "mize_module_list";
|
||||
dontUnpack = true;
|
||||
configurePhase = "";
|
||||
buildPhase = ''
|
||||
mkdir -p $out
|
||||
touch $out/modules_to_build
|
||||
|
||||
find ${path} -not -type d -name mize.nix | while read p; do
|
||||
(echo "$p" >> $out/modules_to_build; echo "found module $p")
|
||||
done
|
||||
|
||||
exit 0
|
||||
'';
|
||||
};
|
||||
|
||||
findModules = path: let
|
||||
mize_module_no_externals = builtins.getEnv "MIZE_MODULE_NO_EXTERNALS";
|
||||
module_list_string = builtins.readFile "${module_list_drv path}/modules_to_build";
|
||||
module_list = pkgs.lib.lists.remove "" (pkgs.lib.strings.splitString "\n" module_list_string);
|
||||
getExternals = path: map findModules ((pkgs.callPackage ((import path).externals or (args: [])) {}));
|
||||
in module_list ++ (if mize_module_no_externals != "" then [] else (map getExternals module_list));
|
||||
|
||||
|
||||
modulesFileList = let
|
||||
from_mize_modules_repo = findModules mize_modules;
|
||||
mize_module_no_repo = builtins.getEnv "MIZE_MODULE_NO_REPO";
|
||||
in pkgs.lib.lists.flatten (from_env_var ++ (if mize_module_no_repo != "" then [] else from_mize_modules_repo) ++ (findModules self));
|
||||
|
||||
mize_module_path = builtins.getEnv "MIZE_MODULE_PATH";
|
||||
dirs_from_path = pkgs.lib.lists.remove "" (pkgs.lib.strings.splitString ":" mize_module_path);
|
||||
dirs_in_nix_store = map (path: builtins.fetchGit {
|
||||
url = path;
|
||||
}) dirs_from_path;
|
||||
from_env_var = map findModules dirs_in_nix_store;
|
||||
|
||||
|
||||
|
||||
buildMizeForSystem = system: let
|
||||
hostSystem = getCrossSystem system;
|
||||
|
||||
pkgsCross = import nixpkgs { inherit buildSystem hostSystem; localSystem = buildSystem; overlays = [ rust-overlay.overlays.default ]; };
|
||||
|
||||
pkgsNative = import nixpkgs { inherit buildSystem; overlays = [ rust-overlay.overlays.default ]; };
|
||||
|
||||
|
||||
|
||||
|
||||
craneLib =
|
||||
if hostSystem.kernel.name == "windows"
|
||||
then
|
||||
(crane.mkLib pkgs).overrideToolchain (fenix.packages.${buildSystem}.combine [
|
||||
#fenix.packages.${buildSystem}.minimal.rustc
|
||||
#fenix.packages.${buildSystem}.minimal.cargo
|
||||
fenix.packages.${buildSystem}.nightly.toolchain
|
||||
fenix.packages.${buildSystem}.targets."${hostSystem.cpu.name}-pc-windows-gnu".stable.toolchain
|
||||
])
|
||||
|
||||
else if hostSystem.cpu.name == "wasm32"
|
||||
then
|
||||
(crane.mkLib pkgs).overrideToolchain (fenix.packages.${buildSystem}.combine [
|
||||
fenix.packages.${buildSystem}.targets.wasm32-unknown-unknown.latest.toolchain
|
||||
fenix.packages.${buildSystem}.latest.toolchain
|
||||
])
|
||||
else if hostSystem.name == "x86_64-linux-gnu"
|
||||
then
|
||||
builtins.trace "x86_64-linux-gnu hackfix...."
|
||||
(crane.mkLib pkgs).overrideToolchain (fenix.packages.${buildSystem}.combine [
|
||||
fenix.packages.${buildSystem}.stable.toolchain
|
||||
])
|
||||
|
||||
else
|
||||
(crane.mkLib pkgsCross).overrideToolchain (p: fenix.packages.${buildSystem}.stable.toolchain)
|
||||
;
|
||||
|
||||
toolchain_version_drv = pkgs.stdenv.mkDerivation {
|
||||
name = "toolchain_version_drv";
|
||||
dontUnpack = true;
|
||||
configurePhase = "";
|
||||
buildPhase = ''
|
||||
mkdir -p $out
|
||||
touch $out/rustc-version
|
||||
|
||||
echo hiiiiiiiiiiiiiiiiiiiiiiii
|
||||
#echo 'rustc 1.80.1 (3f5fd8dd4 2024-08-06)' > $out/rustc-version
|
||||
${craneLib.cargo}/bin/rustc --version > $out/rustc-version
|
||||
|
||||
exit 0
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
|
||||
mkSelString = attrs: builtins.toJSON (attrs // {
|
||||
inherit toolchain_version;
|
||||
system = hostSystem.name;
|
||||
mize_version = "0.0.1";
|
||||
});
|
||||
|
||||
|
||||
toolchain_version = pkgs.lib.strings.removeSuffix "\n" (builtins.readFile "${toolchain_version_drv}/rustc-version");
|
||||
|
||||
|
||||
mkMizeModule = attrs: (if builtins.hasAttr "drvFunc" attrs then attrs.drvFunc else pkgsCross.stdenv.mkDerivation) ( rec {
|
||||
name = attrs.modName;
|
||||
inherit (attrs) modName;
|
||||
selector_string = mkSelString (attrs.select or {} // {
|
||||
inherit (attrs) modName;
|
||||
});
|
||||
hash = builtins.substring 0 32 (builtins.hashString "sha256" selector_string);
|
||||
}
|
||||
// (lib.attrsets.removeAttrs attrs ["drvFunc"] )
|
||||
);
|
||||
|
||||
|
||||
|
||||
########## build a Rust Module
|
||||
mkMizeRustModule = attrs: mkMizeModule (
|
||||
# general stuff
|
||||
{
|
||||
drvFunc = craneLib.buildPackage;
|
||||
MIZE_BUILD_CONFIG = mizeBuildConfigStr;
|
||||
mizeInstallPhase = attrs.mizeInstallPhase or ''
|
||||
mkdir -p $out/lib/
|
||||
cp $build_dir/target/${hostSystem.nameRust}/$debugOrRelease/libmize_module_${attrs.modName}.so $out/lib/
|
||||
'';
|
||||
mizeBuildPhase = attrs.mizeBuildPhase or ''
|
||||
cargo --color always build --target ${hostSystem.nameRust} ${if builtins.hasAttr "cargoExtraArgs" attrs then attrs.cargoExtraArgs else ""} --manifest-path $build_dir/Cargo.toml --lib
|
||||
'';
|
||||
selector_string = mkSelString (attrs.select or {} // {
|
||||
inherit (attrs) modName;
|
||||
});
|
||||
devShell = if builtins.hasAttr "devShell" attrs then attrs.devShell else mkMizeRustShell {};
|
||||
|
||||
}
|
||||
|
||||
|
||||
# linux specific stuff
|
||||
// (lib.attrsets.optionalAttrs (hostSystem.kernel.name == "linux") {
|
||||
# rename the so library, in case the lib.name in your Cargo.toml is not like mize_module_mylib
|
||||
postInstall = (attrs.postInstall or "") + ''
|
||||
if [ ! -f "$out/lib/libmize_module_${attrs.modName}" ]; then
|
||||
echo RENAMING $out/lib/${attrs.modName}.so to $out/lib/libmize_module_${attrs.modName}.so
|
||||
mv $out/lib/${attrs.modName}.so to $out/lib/libmize_module_${attrs.modName}.so || true
|
||||
|
||||
echo RENAMING $out/lib/${attrs.modName}.a to $out/lib/libmize_module_${attrs.modName}.a
|
||||
mv $out/lib/${attrs.modName}.a to $out/lib/libmize_module_${attrs.modName}.a && true # ignore if there is no .a file || true
|
||||
echo "$FILE"
|
||||
fi
|
||||
'';
|
||||
})
|
||||
|
||||
|
||||
# linux cross stuff
|
||||
// (lib.attrsets.optionalAttrs (hostSystem.kernel.name == "linux" && hostSystem.isCross) {
|
||||
"CARGO_TARGET_${builtins.replaceStrings ["-"] ["_"] (pkgsCross.lib.strings.toUpper hostSystem.nameFull)}_LINKER" = "${pkgsCross.stdenv.cc.targetPrefix}cc";
|
||||
HOST_CC = "${pkgsCross.stdenv.cc.nativePrefix}cc";
|
||||
TARGET_CC = "${pkgsCross.stdenv.cc.targetPrefix}cc";
|
||||
CARGO_BUILD_TARGET = hostSystem.nameFull;
|
||||
nativeBuildInputs = attrs.nativeBuildInputs or [] ++ [
|
||||
pkgsCross.stdenv.cc
|
||||
];
|
||||
})
|
||||
|
||||
# wasm stuff
|
||||
// (lib.attrsets.optionalAttrs (hostSystem.cpu.name == "wasm32") {
|
||||
CARGO_BUILD_TARGET = "wasm32-unknown-unknown";
|
||||
|
||||
# checks fail on wasm
|
||||
doCheck = false;
|
||||
})
|
||||
|
||||
|
||||
# add windows stuff
|
||||
// (lib.attrsets.optionalAttrs (hostSystem.kernel.name == "windows") {
|
||||
strictDeps = true;
|
||||
doCheck = false;
|
||||
|
||||
CARGO_BUILD_TARGET = "${hostSystem.cpu.name}-pc-windows-gnu";
|
||||
|
||||
# fixes issues related to libring
|
||||
TARGET_CC = "${pkgs.pkgsCross.mingwW64.stdenv.cc}/bin/${pkgs.pkgsCross.mingwW64.stdenv.cc.targetPrefix}cc";
|
||||
|
||||
#fixes issues related to openssl
|
||||
OPENSSL_DIR = "${pkgs.openssl.dev}";
|
||||
OPENSSL_LIB_DIR = "${pkgs.openssl.out}/lib";
|
||||
OPENSSL_INCLUDE_DIR = "${pkgs.openssl.dev}/include/";
|
||||
|
||||
depsBuildBuild = [
|
||||
pkgs.pkgsCross.mingwW64.stdenv.cc
|
||||
pkgs.pkgsCross.mingwW64.windows.pthreads
|
||||
];
|
||||
})
|
||||
|
||||
|
||||
# add the attrs passed to mkMizeRustModule
|
||||
// attrs
|
||||
|
||||
);
|
||||
|
||||
|
||||
|
||||
buildModule = path: extraArgs: pkgs.callPackage ((import path).module or (attrs: null)) ({
|
||||
inherit buildMizeForSystem mizeBuildConfig mizeBuildConfigStr;
|
||||
inherit mkSelString craneLib toolchain_version;
|
||||
inherit mkMizeModule mkMizeRustModule buildModule findModules hostSystem pkgsCross pkgsNative mkMizeRustShell;
|
||||
inherit fenix;
|
||||
mize_version = "0.0.1";
|
||||
} // extraArgs );
|
||||
|
||||
buildLib = path: extraArgs: pkgs.callPackage ((import path).lib or (args: {})) {
|
||||
inherit mkSelString craneLib toolchain_version;
|
||||
inherit mkMizeModule mkMizeRustModule buildModule findModules hostSystem pkgsCross pkgsNative mkMizeRustShell;
|
||||
mize_version = "0.0.1";
|
||||
};
|
||||
|
||||
|
||||
mizeBuildConfig = {
|
||||
namespace = "mize.buildtime.ns";
|
||||
module_url = "c2vi.dev";
|
||||
selector = builtins.fromJSON (mkSelString {});
|
||||
};
|
||||
|
||||
mizeBuildConfigStr = let
|
||||
settingsFormat = pkgs.formats.toml { };
|
||||
in settingsFormat.generate "mize-build-config.toml" {
|
||||
config = mizeBuildConfig;
|
||||
};
|
||||
|
||||
|
||||
################# dev Shels ###################
|
||||
|
||||
mkMizeRustShell = attrs: mkMizeModuleShell (attrs // {
|
||||
shellHook = ''
|
||||
mize_project_root=$(${lib.getExe pkgs.git} rev-parse --show-toplevel)
|
||||
export MIZE_CONFIG_FILES=$mize_project_root/mize_config.toml
|
||||
'';
|
||||
#_shell_type = "rust";
|
||||
nativeBuildInputs = attrs.nativeBuildInputs or [] ++ [
|
||||
pkgs.wasm-pack
|
||||
pkgs.dioxus-cli
|
||||
pkgs.spacetimedb
|
||||
pkgs.deno
|
||||
pkgs.pkg-config
|
||||
pkgs.gobject-introspection
|
||||
pkgs.gobject-introspection.dev
|
||||
|
||||
# thanks to: https://github.com/NixOS/nixpkgs/pull/496279/changes
|
||||
(pkgs.buildWasmBindgenCli rec {
|
||||
src = pkgs.fetchCrate {
|
||||
pname = "wasm-bindgen-cli";
|
||||
version = "0.2.114";
|
||||
hash = "sha256-xrCym+rFY6EUQFWyWl6OPA+LtftpUAE5pIaElAIVqW0=";
|
||||
};
|
||||
|
||||
cargoDeps = pkgs.rustPlatform.fetchCargoVendor {
|
||||
inherit src;
|
||||
inherit (src) pname version;
|
||||
hash = "sha256-Z8+dUXPQq7S+Q7DWNr2Y9d8GMuEdSnq00quUR0wDNPM=";
|
||||
};
|
||||
})
|
||||
(fenix.packages."x86_64-linux".combine [
|
||||
fenix.packages."x86_64-linux".latest.toolchain
|
||||
fenix.packages."x86_64-linux".targets.wasm32-unknown-unknown.latest.toolchain
|
||||
])
|
||||
|
||||
# the shell script, to mk the dist folder, for a standard rust module
|
||||
(pkgs.writeShellApplication {
|
||||
name = "mkdist";
|
||||
# should we use the folder, that cargo locate-project gives us??? or just cp ./target/debug/
|
||||
text = ''
|
||||
mkdir -p ./dist
|
||||
mkdir -p ./dist/lib
|
||||
|
||||
cp ./target/debug/libmize_module*.so ./dist/lib
|
||||
cp ./target/debug/libmize_module*.a ./dist/lib || true
|
||||
|
||||
'';
|
||||
})
|
||||
];
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
at-spi2-atk
|
||||
atkmm
|
||||
cairo
|
||||
gdk-pixbuf
|
||||
glib
|
||||
gtk3
|
||||
harfbuzz
|
||||
librsvg
|
||||
libsoup_3
|
||||
pango
|
||||
webkitgtk_4_1
|
||||
openssl
|
||||
wasm-bindgen-cli
|
||||
lld_20
|
||||
xdotool
|
||||
];
|
||||
|
||||
LD_LIBRARY_PATH = with pkgs; pkgs.lib.makeLibraryPath [
|
||||
xdotool
|
||||
webkitgtk_4_1
|
||||
pango
|
||||
openssl
|
||||
at-spi2-atk
|
||||
atkmm
|
||||
cairo
|
||||
gdk-pixbuf
|
||||
glib
|
||||
gtk3
|
||||
harfbuzz
|
||||
librsvg
|
||||
libsoup_3
|
||||
];
|
||||
|
||||
|
||||
});
|
||||
|
||||
mkMizeModuleShell = attrs: pkgs.mkShell (attrs // {
|
||||
MIZE_BUILD_CONFIG = mizeBuildConfigStr;
|
||||
IS_MIZE_DEV_SHELL = "true";
|
||||
});
|
||||
|
||||
|
||||
################# output attrset ###################
|
||||
|
||||
in rec {
|
||||
|
||||
main = modules.mize;
|
||||
|
||||
system = hostSystem;
|
||||
|
||||
|
||||
modules = builtins.listToAttrs ( map ( mod: { name = mod.modName; value = mod; } ) modulesList );
|
||||
|
||||
# for debugging
|
||||
|
||||
modulesLibList = map (mod: buildLib mod {}) modulesFileList;
|
||||
modulesLib = pkgs.lib.lists.foldr (a: b: b // a) {} modulesLibList;
|
||||
modulesList = pkgs.lib.lists.remove null (map (mod: (buildModule mod modulesLib)) modulesFileList);
|
||||
|
||||
inherit toolchain_version_drv pkgsCross craneLib;
|
||||
|
||||
inherit mize_module_path dirs_from_path dirs_in_nix_store from_env_var;
|
||||
|
||||
};
|
||||
|
||||
|
||||
mkInstallPhase = mize: ''
|
||||
# install mize
|
||||
mkdir -p $out/mize/${mize.system.name}
|
||||
|
||||
cp -r ${mize.main}/* $out/mize/${mize.system.name}/
|
||||
|
||||
# intall the modules
|
||||
${mkModulesInstallPhase mize.modulesList}
|
||||
'';
|
||||
|
||||
mkModulesInstallPhase = modules: pkgs.lib.concatStringsSep "\n" (map mkModuleInstallPhase modules);
|
||||
|
||||
mkModuleInstallPhase = module: let
|
||||
hash = module.hash;
|
||||
in ''
|
||||
echo got module: ${module.name}
|
||||
echo out: $out
|
||||
echo hash: ${hash}
|
||||
cp --no-preserve=mode,ownership -r ${module}/* $out/mize/dist/${hash}-${module.modName}
|
||||
${pkgs.gnutar}/bin/tar -czf $out/mize/dist/${hash}-${module.modName}.tar.gz -C ${module} .
|
||||
echo '${module.selector_string}' > $out/mize/dist/${hash}-${module.modName}/selector
|
||||
'';
|
||||
|
||||
dist = systems: stdenv.mkDerivation {
|
||||
name = "mize-dist";
|
||||
dontUnpack = true;
|
||||
|
||||
# so that those binaries run on average linux-gnu systems
|
||||
dontPatchShebangs = true;
|
||||
|
||||
buildPhase = ''
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
mkdir -p $out/mize
|
||||
mkdir -p $out/mize/dist
|
||||
|
||||
'' ;# + pkgs.lib.concatStringsSep "\n" (map mkInstallPhase (map buildMizeForSystem systems));
|
||||
|
||||
|
||||
nativeBuildInputs = [
|
||||
];
|
||||
};
|
||||
|
||||
moduleShells = system: let
|
||||
mizeFor = buildMizeForSystem system;
|
||||
in builtins.listToAttrs ( map ( mod: { name = mod.modName; value = (mod.devShell); } ) mizeFor.modulesList );
|
||||
|
||||
random = systems: rec {
|
||||
|
||||
distInstallPhase = map mkInstallPhase (map buildMizeForSystem systems);
|
||||
mizeList = map buildMizeForSystem systems;
|
||||
mize-x86_64-linux = buildMizeForSystem "x86_64-linux";
|
||||
mize-x86_64-linux-installPhase = mkInstallPhase mize-x86_64-linux;
|
||||
modulesListDrv = module_list_drv mize_modules;
|
||||
inherit modulesFileList;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
{
|
||||
|
||||
module = { mkMizeRustModule, mkMizeRustShell, hostSystem, pkgsCross, pkgs, lib, craneLib, ... }:
|
||||
|
||||
mkMizeRustModule (
|
||||
|
||||
|
||||
# general stuff
|
||||
{
|
||||
modName = "mize";
|
||||
src = ./.;
|
||||
cargoExtraArgs = "--no-default-features --lib";
|
||||
}
|
||||
|
||||
|
||||
|
||||
# linux stuff
|
||||
// (lib.attrsets.optionalAttrs (hostSystem.kernel.name == "linux") {
|
||||
strictDeps = true;
|
||||
cargoExtraArgs = "--bin mize --features target-os";
|
||||
mizeInstallPhase = ''
|
||||
mkdir -p $out
|
||||
cp $build_dir/target/${hostSystem.nameRust}/$debugOrRelease/mize $out/
|
||||
'';
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
# x86_64-linux stuff
|
||||
// (lib.attrsets.optionalAttrs (hostSystem.name == "x86_64-linux-gnu") rec {
|
||||
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkgsCross.buildPackages.pkg-config
|
||||
];
|
||||
|
||||
|
||||
|
||||
buildInputs = [
|
||||
pkgs.openssl
|
||||
];
|
||||
|
||||
devShell = mkMizeRustShell {
|
||||
inherit buildInputs nativeBuildInputs;
|
||||
};
|
||||
|
||||
|
||||
# patch the interpreter to run on most linux-gnu distros
|
||||
# postBuild = "patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 /build/source/target/release/mize";
|
||||
|
||||
})
|
||||
|
||||
# aarch64-linux stuff
|
||||
// (lib.attrsets.optionalAttrs (hostSystem.name == "aarch64-linux-gnu") {
|
||||
# patch the interpreter to run on most linux-gnu distros
|
||||
postBuild = "patchelf --set-interpreter /lib64/ld-linux-aarch64.so.2 /build/source/target/${hostSystem.nameFull}/release/mize";
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
#x86_64-windows stuff
|
||||
// (lib.attrsets.optionalAttrs (hostSystem.name == "x86_64-windows-gnu") {
|
||||
|
||||
strictDeps = true;
|
||||
doCheck = false;
|
||||
|
||||
cargoExtraArgs = "--bin mize --features target-os";
|
||||
|
||||
CARGO_BUILD_TARGET = "${hostSystem.cpu.name}-pc-windows-gnu";
|
||||
|
||||
# fixes issues related to libring
|
||||
TARGET_CC = "${pkgs.pkgsCross.mingwW64.stdenv.cc}/bin/${pkgs.pkgsCross.mingwW64.stdenv.cc.targetPrefix}cc";
|
||||
|
||||
#fixes issues related to openssl
|
||||
OPENSSL_DIR = "${pkgs.openssl.dev}";
|
||||
OPENSSL_LIB_DIR = "${pkgs.openssl.out}/lib";
|
||||
OPENSSL_INCLUDE_DIR = "${pkgs.openssl.dev}/include/";
|
||||
|
||||
depsBuildBuild = [
|
||||
pkgs.pkgsCross.mingwW64.stdenv.cc
|
||||
pkgs.pkgsCross.mingwW64.windows.pthreads
|
||||
];
|
||||
})
|
||||
|
||||
|
||||
|
||||
#browser stuff
|
||||
// (lib.attrsets.optionalAttrs (hostSystem.name == "wasm32-none-unknown") rec {
|
||||
|
||||
cargoArtifacts = craneLib.buildDepsOnly ({
|
||||
src = ./.;
|
||||
doCheck = false; # tests does not work in wasm
|
||||
CARGO_BUILD_TARGET = "wasm32-unknown-unknown";
|
||||
cargoExtraArgs = "--features target-wasm --no-default-features";
|
||||
RUSTFLAGS="-C linker=wasm-ld";
|
||||
buildInputs = with pkgs; [ cargo-binutils lld ];
|
||||
});
|
||||
|
||||
mizeBuildPhase = ''
|
||||
cd $build_dir
|
||||
RUST_LOG=off wasm-pack build --target no-modules --dev --out-dir $out -- --features target-wasm --no-default-features
|
||||
cat $build_dir/src/platform/wasm/init.js >> $out/mize.js
|
||||
'';
|
||||
mizeInstallPhase = "";
|
||||
|
||||
doInstallCargoArtifacts = false;
|
||||
|
||||
doCheck = false;
|
||||
|
||||
buildPhaseCargoCommand = ''
|
||||
mkdir -p $out/pkg
|
||||
|
||||
HOME=$(mktemp -d fake-homeXXXX) wasm-pack build --target no-modules --out-dir $out/pkg --scope=c2vi -- --features target-wasm --no-default-features
|
||||
'';
|
||||
|
||||
postInstall = ''
|
||||
rm -rf $out/target.tar.zst
|
||||
|
||||
cat $src/src/platform/wasm/init.js >> $out/pkg/mize.js
|
||||
'';
|
||||
|
||||
nativeBuildInputs = with pkgs; [ wasm-bindgen-cli binaryen wasm-pack ];
|
||||
|
||||
devShell = mkMizeRustShell {
|
||||
inherit nativeBuildInputs;
|
||||
};
|
||||
|
||||
})
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
@@ -53,9 +53,13 @@ pub fn gather_config(mize: &mut Mize) -> MizeResult<()> {
|
||||
let mut data = ItemData::from_toml(content.as_str())?;
|
||||
println!("config data: {data}");
|
||||
for path in data.get_paths_recursive()? {
|
||||
let conf_name = path.replace("/", ".");
|
||||
let mut conf_name = path.replace("/", ".");
|
||||
if conf_name.starts_with(".") {
|
||||
conf_name.remove(0);
|
||||
}
|
||||
println!("adding config {conf_name} from config file {config_file_path}");
|
||||
let val = data.get_path(path.split("/").collect::<Vec<&str>>())?;
|
||||
println!("path: {:?}", path);
|
||||
let val = data.get_path(path.split("/").filter(|s| s != &"").collect::<Vec<&str>>())?;
|
||||
match config_opts.get_mut(&conf_name) {
|
||||
Some(opt) => {
|
||||
opt.val = Some(val);
|
||||
|
||||
@@ -707,6 +707,7 @@ impl Mize {
|
||||
#[cfg(feature = "target-os")]
|
||||
let handle = thread::spawn(move || to_spawn());
|
||||
|
||||
#[cfg(feature = "target-os")]
|
||||
threads_inner.push((*next_thread_id, name.to_owned(), Some(handle)));
|
||||
|
||||
#[cfg(feature = "target-wasm ")]
|
||||
@@ -905,9 +906,10 @@ impl Mize {
|
||||
}
|
||||
|
||||
pub fn run(&mut self) -> MizeResult<()> {
|
||||
let mut parts = self.parts.lock().unwrap();
|
||||
for part in parts.values_mut() {
|
||||
part.as_deref_mut().unwrap().run(&mut self.clone())?;
|
||||
let part_names = self.part_names();
|
||||
for part_name in part_names {
|
||||
let mut part = self.get_part(part_name)?;
|
||||
part.run(&mut self.clone())?;
|
||||
}
|
||||
let mut threads_inner = self.threads.lock().unwrap();
|
||||
for (id, name, handle) in threads_inner.drain(..) {
|
||||
@@ -922,8 +924,12 @@ impl Mize {
|
||||
&mut self,
|
||||
name: &str,
|
||||
) -> MizeResult<MizePartGuard<T>> {
|
||||
println!("Getting part native hiiiiiii");
|
||||
let mut dyn_guard = self.get_part(name)?;
|
||||
println!("Getting part native hiiiiiii two");
|
||||
let part = dyn_guard.part.take().unwrap();
|
||||
println!("Getting part native hiiiiiii three");
|
||||
drop(dyn_guard);
|
||||
let concrete_part = part.into_any().downcast::<T>().unwrap();
|
||||
Ok(MizePartGuard {
|
||||
mize: self.clone(),
|
||||
|
||||
@@ -29,6 +29,8 @@ tracing = { version = "0.1.44", optional = true }
|
||||
tower = { version = "0.5", optional = true }
|
||||
tower-sessions = { version = "0.14.0", optional = true }
|
||||
tower-http = { version = "0.6.8", features = ["trace"] }
|
||||
webbrowser = { version = "1.2.0", optional = true }
|
||||
base64 = { version = "0.22.1", optional = true }
|
||||
|
||||
[[bin]]
|
||||
name = "ppc"
|
||||
@@ -41,7 +43,7 @@ name = "ppc"
|
||||
|
||||
[features]
|
||||
default = ["target-os"]
|
||||
target-os = [ "clap", "mize/target-os", "marts/target-os", "server", "tracing" ]
|
||||
target-os = [ "clap", "mize/target-os", "marts/target-os", "server", "tracing", "webbrowser", "base64" ]
|
||||
target-obsidian = [ "js-sys", "wasm-bindgen", "mize/target-wasm", "marts/target-wasm" ]
|
||||
server = [ "axum", "axum-extra", "openidconnect", "serde", "serde_json", "reqwest", "rand", "url", "time", "tokio", "dioxus", "dioxus-ssr", "html-escape", "axum-oidc", "tower", "tower-sessions" ]
|
||||
|
||||
|
||||
221
packages/ppc/auth/client.rs
Normal file
221
packages/ppc/auth/client.rs
Normal file
@@ -0,0 +1,221 @@
|
||||
use base64::{
|
||||
Engine,
|
||||
alphabet::STANDARD,
|
||||
engine::{DecodePaddingMode, GeneralPurpose, GeneralPurposeConfig},
|
||||
};
|
||||
use clap::Command;
|
||||
use mize::{Mize, MizeError, MizePart, MizeResult, mize_err, mize_part};
|
||||
use openidconnect::{
|
||||
AuthorizationCode, ClientId, CsrfToken, IssuerUrl, Nonce, OAuth2TokenResponse,
|
||||
PkceCodeChallenge, PkceCodeVerifier, RedirectUrl, RefreshToken, Scope,
|
||||
core::{CoreAuthenticationFlow, CoreClient, CoreProviderMetadata},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
io::{self, Write},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
#[mize_part]
|
||||
pub struct ClientAuth {
|
||||
mize: Mize,
|
||||
secrets: Option<ClientSecrets>,
|
||||
}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct ClientSecrets {
|
||||
id_token: String,
|
||||
access_token: String,
|
||||
refresh_token: String,
|
||||
}
|
||||
|
||||
impl MizePart for ClientAuth {
|
||||
fn name(&self) -> &'static str {
|
||||
"client_auth"
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientAuth {
|
||||
pub fn id_token(&self) -> MizeResult<&str> {
|
||||
if self.secrets.is_none() {
|
||||
return Err(mize_err!("Client not logged in"));
|
||||
}
|
||||
Ok(&self.secrets.as_ref().unwrap().id_token)
|
||||
}
|
||||
|
||||
pub fn access_token(&self) -> MizeResult<&str> {
|
||||
if self.secrets.is_none() {
|
||||
return Err(mize_err!("Client not logged in"));
|
||||
}
|
||||
Ok(&self.secrets.as_ref().unwrap().access_token)
|
||||
}
|
||||
|
||||
pub fn refresh_token(&self) -> MizeResult<&str> {
|
||||
if self.secrets.is_none() {
|
||||
return Err(mize_err!("Client not logged in"));
|
||||
}
|
||||
Ok(&self.secrets.as_ref().unwrap().refresh_token)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn client_auth(mize: &mut Mize) -> MizeResult<()> {
|
||||
let mize_clone = mize.clone();
|
||||
|
||||
let secrets = match read_secrets(mize) {
|
||||
Ok(secrets) => Some(secrets),
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
let mut cli = mize.get_part_native::<marts::CliPart>("cli")?;
|
||||
cli.subcommand(Command::new("login"), |_, mut mize| {
|
||||
let secrets = mize.spawn_async_blocking("client_auth", auth_flow(mize_clone))?;
|
||||
println!("hereeeeee oneeeeeeeeee");
|
||||
let mut auth = mize.get_part_native::<ClientAuth>("client_auth")?;
|
||||
println!("hereeeeee two");
|
||||
write_secrets(&mut mize, &secrets)?;
|
||||
auth.secrets = Some(secrets);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
mize.register_part(Box::new(ClientAuth {
|
||||
secrets,
|
||||
mize: mize.clone(),
|
||||
}))
|
||||
}
|
||||
|
||||
fn read_secrets(mize: &mut Mize) -> MizeResult<ClientSecrets> {
|
||||
let mize_dir = mize.get_config("data_dir")?.value_string()?;
|
||||
let secrets_file_path = PathBuf::from(mize_dir).join("client_secrets.json");
|
||||
|
||||
let secrets_string = std::fs::read_to_string(secrets_file_path)?;
|
||||
let secrets: ClientSecrets = serde_json::from_str(&secrets_string)?;
|
||||
Ok(secrets)
|
||||
}
|
||||
|
||||
fn write_secrets(mize: &mut Mize, secrets: &ClientSecrets) -> MizeResult<()> {
|
||||
let mize_dir = mize.get_config("data_dir")?.value_string()?;
|
||||
let secrets_file_path = PathBuf::from(mize_dir).join("client_secrets.json");
|
||||
|
||||
let secrets_string = serde_json::to_string(secrets)?;
|
||||
std::fs::write(secrets_file_path, secrets_string)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Combined<'a> {
|
||||
code: &'a str,
|
||||
state: &'a str,
|
||||
}
|
||||
|
||||
async fn auth_flow(mut mize: Mize) -> MizeResult<ClientSecrets> {
|
||||
// ===== CONFIG =====
|
||||
// Replace these with your issuer, client id and the public redirect URL served by the axum app.
|
||||
|
||||
let issuer = mize.get_config("auth.client.issuer")?.value_string()?;
|
||||
let client_id = mize.get_config("auth.client.client_id")?.value_string()?;
|
||||
let redirect_url = mize
|
||||
.get_config("auth.client.redirect_url")?
|
||||
.value_string()?;
|
||||
|
||||
let issuer = IssuerUrl::new(issuer)?;
|
||||
let client_id = ClientId::new(client_id);
|
||||
let redirect_uri = RedirectUrl::new(redirect_url)?;
|
||||
|
||||
// Discover provider metadata
|
||||
let provider_metadata =
|
||||
CoreProviderMetadata::discover_async(issuer, &openidconnect::reqwest::Client::new())
|
||||
.await?;
|
||||
|
||||
let client = CoreClient::from_provider_metadata(
|
||||
provider_metadata,
|
||||
client_id,
|
||||
None, // no client secret for public clients
|
||||
)
|
||||
.set_redirect_uri(redirect_uri);
|
||||
|
||||
// ===== PKCE + state + nonce =====
|
||||
let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();
|
||||
let csrf_token = CsrfToken::new_random();
|
||||
let csrf_token_clone = csrf_token.clone();
|
||||
let nonce = Nonce::new_random();
|
||||
|
||||
// Build the authorization URL - include code_challenge and state
|
||||
let (auth_url, _csrf_token_returned, _nonce_returned) = client
|
||||
.authorize_url(
|
||||
CoreAuthenticationFlow::AuthorizationCode,
|
||||
move || csrf_token_clone.clone(),
|
||||
move || nonce.clone(),
|
||||
)
|
||||
.set_pkce_challenge(pkce_challenge)
|
||||
.add_scope(Scope::new("openid".to_string()))
|
||||
.add_scope(Scope::new("profile".to_string()))
|
||||
.url();
|
||||
|
||||
println!("Opening browser to authenticate...");
|
||||
println!(
|
||||
"If your browser does not open automatically, visit:\n\n{}\n",
|
||||
auth_url
|
||||
);
|
||||
|
||||
// Try to open browser (best-effort)
|
||||
if let Err(e) = webbrowser::open(auth_url.as_str()) {
|
||||
eprintln!("Failed to open browser automatically: {}", e);
|
||||
}
|
||||
|
||||
println!("When the authorization completes, the web page will show the code (and state).");
|
||||
print!("Paste login string here: ");
|
||||
io::stdout().flush()?;
|
||||
|
||||
// Read user input
|
||||
let mut input = String::new();
|
||||
io::stdin().read_line(&mut input)?;
|
||||
let input = input.trim();
|
||||
|
||||
if input.is_empty() {
|
||||
return Err(mize_err!("No login string provided"));
|
||||
}
|
||||
|
||||
let base64_engine = GeneralPurpose::new(
|
||||
&STANDARD,
|
||||
GeneralPurposeConfig::new().with_decode_padding_mode(DecodePaddingMode::RequireNone),
|
||||
);
|
||||
|
||||
let json_bytes = base64_engine.decode(input)?;
|
||||
let json_str = String::from_utf8(json_bytes)?;
|
||||
let combined: Combined = serde_json::from_str(json_str.as_str())?;
|
||||
|
||||
if combined.state != csrf_token.secret() {
|
||||
return Err(mize_err!(
|
||||
"State mismatch: pasted state does not match expected value"
|
||||
));
|
||||
} else {
|
||||
println!("State is valid");
|
||||
};
|
||||
|
||||
// Perform token exchange
|
||||
let token_response = client
|
||||
.exchange_code(AuthorizationCode::new(combined.code.to_string()))?
|
||||
.set_pkce_verifier(PkceCodeVerifier::new(pkce_verifier.secret().to_string()))
|
||||
.request_async(&openidconnect::reqwest::Client::new())
|
||||
.await?;
|
||||
|
||||
let id_token = token_response
|
||||
.extra_fields()
|
||||
.id_token()
|
||||
.ok_or(mize_err!("no id_token"))?;
|
||||
|
||||
//let refresh = token_response.refresh_token();
|
||||
|
||||
println!("\n=== Token response ===");
|
||||
println!("Access token: {:?}", token_response.access_token().secret());
|
||||
println!("ID token: {}", id_token.to_string());
|
||||
//println!("Refresh token: {}", refresh.secret());
|
||||
|
||||
Ok(ClientSecrets {
|
||||
id_token: id_token.to_string(),
|
||||
access_token: token_response.access_token().secret().to_string(),
|
||||
refresh_token: "".to_string(),
|
||||
})
|
||||
}
|
||||
@@ -16,3 +16,8 @@ mod website;
|
||||
pub use platform::os::server::server;
|
||||
#[cfg(feature = "target-os")]
|
||||
pub use platform::os::ui;
|
||||
|
||||
pub mod auth {
|
||||
pub mod client;
|
||||
}
|
||||
pub use auth::client::client_auth;
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
export function add(a: number, b: number): number {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
// Learn more at https://docs.deno.com/runtime/manual/examples/module_metadata#concepts
|
||||
if (import.meta.main) {
|
||||
console.log("Add 2 + 3 =", add(2, 3));
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import { assertEquals } from "@std/assert";
|
||||
import { add } from "./main.ts";
|
||||
|
||||
Deno.test(function addTest() {
|
||||
assertEquals(add(2, 3), 5);
|
||||
});
|
||||
@@ -22,6 +22,7 @@ fn os_main(mize: &mut Mize) -> MizeResult<()> {
|
||||
marts::habitica(mize)?;
|
||||
marts::c2vi(mize)?;
|
||||
ppc::server(mize)?;
|
||||
ppc::client_auth(mize)?;
|
||||
|
||||
let mut cli = mize.get_part_native::<marts::CliPart>("cli")?;
|
||||
|
||||
|
||||
@@ -12,6 +12,11 @@ use axum_oidc::{
|
||||
EmptyAdditionalClaims, OidcAuthLayer, OidcClaims, OidcClient, OidcLoginLayer,
|
||||
OidcRpInitiatedLogout, error::MiddlewareError,
|
||||
};
|
||||
use base64::{
|
||||
Engine,
|
||||
alphabet::STANDARD,
|
||||
engine::{GeneralPurpose, GeneralPurposeConfig},
|
||||
};
|
||||
use clap::Command;
|
||||
use dioxus::prelude::*;
|
||||
use mize::Mize;
|
||||
@@ -99,7 +104,8 @@ pub async fn start_server(mize: &mut Mize) -> MizeResult<()> {
|
||||
.layer(session_layer)
|
||||
.layer(tower_http::trace::TraceLayer::new_for_http())
|
||||
// not authenticated routes
|
||||
.route("/", get(ppc_main_page));
|
||||
.route("/", get(ppc_main_page))
|
||||
.route("/oidc_display_code_and_state", get(display_code_and_state));
|
||||
|
||||
tracing::info!("Running on http://localhost:3000");
|
||||
|
||||
@@ -136,3 +142,55 @@ async fn maybe_authenticated(
|
||||
async fn logout(logout: OidcRpInitiatedLogout) -> impl IntoResponse {
|
||||
logout.with_post_logout_redirect(Uri::from_static("https://localhost:3000"))
|
||||
}
|
||||
|
||||
// src/web_callback.rs
|
||||
use axum::{extract::Query, response::Html};
|
||||
use html_escape::encode_text;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct CallbackParams {
|
||||
pub code: Option<String>,
|
||||
pub state: Option<String>,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Combined<'a> {
|
||||
code: &'a str,
|
||||
state: &'a str,
|
||||
}
|
||||
|
||||
async fn display_code_and_state(Query(params): Query<CallbackParams>) -> Html<String> {
|
||||
// Safe fallbacks
|
||||
let code = params.code.clone().unwrap_or_default();
|
||||
let state = params.state.clone().unwrap_or_default();
|
||||
let error = params.error.clone().unwrap_or_default();
|
||||
|
||||
// Create JSON object and base64 encode it
|
||||
let combined = Combined {
|
||||
code: &code,
|
||||
state: &state,
|
||||
};
|
||||
// serde_json::to_string should succeed for simple strings; fallback to empty JSON on error
|
||||
let json = serde_json::to_string(&combined)
|
||||
.unwrap_or_else(|_| "{\"code\":\"\",\"state\":\"\"}".into());
|
||||
let base64_engine = GeneralPurpose::new(
|
||||
&STANDARD,
|
||||
GeneralPurposeConfig::new().with_encode_padding(false),
|
||||
);
|
||||
let b64 = base64_engine.encode(json);
|
||||
|
||||
let b64_escaped = encode_text(&b64);
|
||||
let error_escaped = encode_text(&error);
|
||||
println!("err: {}", error_escaped);
|
||||
println!("b: {}", b64_escaped);
|
||||
|
||||
let html = match error_escaped.as_ref() {
|
||||
"" => format!("Copy this into your client: {}", b64_escaped),
|
||||
_ => format!("An Error occured: {}", error_escaped),
|
||||
};
|
||||
|
||||
Html(html)
|
||||
}
|
||||
|
||||
13
packages/spacetime-module-ppc/Cargo.toml
Normal file
13
packages/spacetime-module-ppc/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "quickstart_chat"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
spacetimedb = "1.11.*"
|
||||
log = "0.4"
|
||||
36
packages/spacetime-module-ppc/src/lib.rs
Normal file
36
packages/spacetime-module-ppc/src/lib.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use log::*;
|
||||
use spacetimedb::{ReducerContext, Table};
|
||||
|
||||
#[spacetimedb::table(name = person, public)]
|
||||
pub struct CoolPerson {
|
||||
username: String,
|
||||
}
|
||||
|
||||
#[spacetimedb::reducer(init)]
|
||||
pub fn init(_ctx: &ReducerContext) {
|
||||
// Called when the module is initially published
|
||||
info!("hiiiiiii");
|
||||
}
|
||||
|
||||
#[spacetimedb::reducer(client_connected)]
|
||||
pub fn identity_connected(_ctx: &ReducerContext) {
|
||||
// Called everytime a new client connects
|
||||
}
|
||||
|
||||
#[spacetimedb::reducer(client_disconnected)]
|
||||
pub fn identity_disconnected(_ctx: &ReducerContext) {
|
||||
// Called everytime a client disconnects
|
||||
}
|
||||
|
||||
#[spacetimedb::reducer]
|
||||
pub fn add(ctx: &ReducerContext, username: String) {
|
||||
ctx.db.person().insert(CoolPerson { username });
|
||||
}
|
||||
|
||||
#[spacetimedb::reducer]
|
||||
pub fn say_hello(ctx: &ReducerContext) {
|
||||
for person in ctx.db.person().iter() {
|
||||
log::info!("Hello, {}!", person.username);
|
||||
}
|
||||
log::info!("Hello, World!");
|
||||
}
|
||||
Reference in New Issue
Block a user