Compare commits
10 commits
a80283922e
...
53cca3beff
| Author | SHA1 | Date | |
|---|---|---|---|
| 53cca3beff | |||
| a56b537ba4 | |||
| 375fd51a45 | |||
| e1a120dda6 | |||
| 6e59bc3242 | |||
| 4dc2a2e3c5 | |||
| a4a2c0a14b | |||
| 4f44e2e97e | |||
| b94ad2bf97 | |||
| d2c1cc8017 |
12 changed files with 141 additions and 26 deletions
25
docker/Dockerfile
Normal file
25
docker/Dockerfile
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
FROM debian:testing
|
||||||
|
|
||||||
|
RUN ( \
|
||||||
|
set -e; \
|
||||||
|
apt-get -yq update; \
|
||||||
|
apt-get -yq install \
|
||||||
|
build-essential \
|
||||||
|
curl \
|
||||||
|
mdbook \
|
||||||
|
plantuml \
|
||||||
|
vim-nox \
|
||||||
|
; \
|
||||||
|
apt-get clean; \
|
||||||
|
)
|
||||||
|
|
||||||
|
ENV RUSTUP_HOME=/opt/rustup
|
||||||
|
ENV CARGO_HOME=/opt/cargo
|
||||||
|
|
||||||
|
RUN ( \
|
||||||
|
set -e; \
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y ; \
|
||||||
|
chmod 777 /opt/rustup /opt/cargo; \
|
||||||
|
)
|
||||||
|
|
||||||
|
ENV PATH="$PATH:$CARGO_HOME/bin"
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
[inputs]
|
[inputs]
|
||||||
capital = { quantity = { amount=5.75, unit="USDollar" } }
|
capital = { quantity = { amount=2.59, unit="USDollar" } }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
operator = {skills=["vendor interaction"]}
|
operator = {skills=["vendor interaction"]}
|
||||||
|
|
||||||
[action.purchase]
|
[action.purchase]
|
||||||
vendor = [
|
vendor = [
|
||||||
|
"https://acmehydroponics.net/collections/plumbing/products/fill-drain-1-2-fitting",
|
||||||
"https://www.ebay.com/itm/134772441988",
|
"https://www.ebay.com/itm/134772441988",
|
||||||
"https://www.ebay.com/itm/251050375775?var=554293415440",
|
"https://www.ebay.com/itm/251050375775?var=554293415440",
|
||||||
"https://www.ebay.com/itm/251313018420",
|
"https://www.ebay.com/itm/251313018420",
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
[inputs]
|
[inputs]
|
||||||
capital = { quantity = { amount=15.19, unit="USDollar" } }
|
capital = { quantity = { amount=2.49, unit="USDollar" } }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
operator = {skills=["vendor interaction"]}
|
operator = {skills=["vendor interaction"]}
|
||||||
|
|
||||||
[action.purchase]
|
[action.purchase]
|
||||||
vendor = [
|
vendor = [
|
||||||
"https://www.botanicare.com/products/fittings/"
|
"https://www.botanicare.com/products/fittings/",
|
||||||
|
"https://acmehydroponics.net/collections/plumbing/products/fill-drain-1-fitting"
|
||||||
]
|
]
|
||||||
|
|
|
||||||
12
modular-recipes/repos/minimal_hydroponics_setup/filter.toml
Normal file
12
modular-recipes/repos/minimal_hydroponics_setup/filter.toml
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
[inputs]
|
||||||
|
capital = { quantity = { amount=0.96, unit="USDollar" } }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
operator = {skills=["vendor interaction"]}
|
||||||
|
|
||||||
|
[action.purchase]
|
||||||
|
vendor = [
|
||||||
|
"https://acmehydroponics.net/collections/plumbing/products/screen-fitting-plumbing",
|
||||||
|
"https://hydrobuilder.com/products/grow1-ebb-flow-screen-fittings-pack-of-10",
|
||||||
|
"https://www.ebay.com/itm/256644061627"
|
||||||
|
]
|
||||||
|
|
@ -2,8 +2,11 @@
|
||||||
food_safe_bucket_lid = {}
|
food_safe_bucket_lid = {}
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tools = [ "hole saw" ]
|
tools = [ "hack saw" ]
|
||||||
|
|
||||||
[action]
|
[action]
|
||||||
process = """Drill three holes in the lid the right size to fit the 1
|
process = """Use the holes drilled in the `plant_tray_basin` to mark
|
||||||
inch tube, the 1/2 inch tube, and the pump's power cord through."""
|
the `food_safe_bucket_lid`. Cut the lid to make room for the two barb
|
||||||
|
fittings, so the `plant_tray_basin` can sit in the lid comfortably.
|
||||||
|
This cut will also make room for the `nutrient_pump` power cord to
|
||||||
|
exit."""
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
[inputs]
|
||||||
|
barb_fitting_1_inch = {}
|
||||||
|
riser = { quantity = { amount = 2 } }
|
||||||
|
filter = {}
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
operator = {skills=["assembly"]}
|
||||||
|
|
||||||
|
[action]
|
||||||
|
process = """
|
||||||
|
Attach the risers and filter to the barb fitting.
|
||||||
|
"""
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
[inputs]
|
[inputs]
|
||||||
plant_tray_basin = {}
|
plant_tray_basin = {}
|
||||||
clay_pebble_grow_medium = { quantity = { amount=5, unit="Liter" } }
|
clay_pebble_grow_medium = { quantity = { amount=5, unit="Liter" } }
|
||||||
barb_fitting_1_inch = {}
|
pump_fitting = {}
|
||||||
barb_fitting_1_2_inch = {}
|
overflow_fitting = {}
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tools = [ "hack saw" ]
|
tools = [ "hack saw" ]
|
||||||
|
|
||||||
[action]
|
[action]
|
||||||
process = """Attach the two fittings.
|
process = """
|
||||||
|
* Attach the pump fitting.
|
||||||
Add the grow medium."""
|
* Attach the overflow fitting.
|
||||||
|
* Add the grow medium.
|
||||||
|
"""
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,20 @@ plant_tray_basin = { comment = "Alternatively use commercial plastic bus tubs."
|
||||||
food_safe_5_gallon_bucket = {}
|
food_safe_5_gallon_bucket = {}
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tools = [ "hack saw", "step drill" ]
|
tools = [ "hack saw", "step drill correct size for both barb fittings" ]
|
||||||
|
|
||||||
[action]
|
[action]
|
||||||
process = """* Cut the top of the bucket off, leaving a kind of deep dish
|
process = """
|
||||||
or bowl that will holds the plant growth medium and the plants.
|
|
||||||
|
|
||||||
* Drill holes for the two fittings."""
|
* Drill holes for the two fittings. The holes should be pretty close
|
||||||
|
together, but far enough apart that there's sufficient room for the nuts
|
||||||
|
that compress the barb fitting gaskets.
|
||||||
|
|
||||||
|
* Temporarily install the overflow fitting, and mark the wall of the
|
||||||
|
bucket a few inches above the top of the overflow fitting.
|
||||||
|
|
||||||
|
* Cut the top of the bucket off at the mark. This leaves a kind of deep
|
||||||
|
dish or bowl that will holds the plant growth medium and the plants.
|
||||||
|
a few inches above the top of the overflow fitting.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
[inputs]
|
||||||
|
barb_fitting_1_2_inch = {}
|
||||||
|
filter = {}
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
operator = {skills=["assembly"]}
|
||||||
|
|
||||||
|
[action]
|
||||||
|
process = """
|
||||||
|
Attach the filter to the barb fitting.
|
||||||
|
"""
|
||||||
11
modular-recipes/repos/minimal_hydroponics_setup/riser.toml
Normal file
11
modular-recipes/repos/minimal_hydroponics_setup/riser.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
[inputs]
|
||||||
|
capital = { quantity = { amount=0.97, unit="USDollar" } }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
operator = {skills=["vendor interaction"]}
|
||||||
|
|
||||||
|
[action.purchase]
|
||||||
|
vendor = [
|
||||||
|
"https://acmehydroponics.net/collections/plumbing/products/extension-fitting-plumbing",
|
||||||
|
"https://www.ebay.com/itm/256644065109"
|
||||||
|
]
|
||||||
|
|
@ -3,26 +3,47 @@ use clap::Parser;
|
||||||
#[derive(Debug, clap::Parser)]
|
#[derive(Debug, clap::Parser)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
struct Args {
|
struct Args {
|
||||||
/// The name of the recipe to build.
|
/// Directories containing repos, eg "../my-repos".
|
||||||
target: String,
|
|
||||||
|
|
||||||
/// Directories containing repos.
|
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
// repo: String,
|
|
||||||
repo: Vec<String>,
|
repo: Vec<String>,
|
||||||
|
|
||||||
|
/// Type of behavior/output.
|
||||||
|
#[command(subcommand)]
|
||||||
|
command: Commands,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(clap::Subcommand, Debug)]
|
||||||
|
enum Commands {
|
||||||
|
/// Produce an mdbook of the specified recipe.
|
||||||
|
Mdbook {
|
||||||
|
/// The name of the recipe to create MD Book for, eg "my_widget".
|
||||||
|
target: String,
|
||||||
|
},
|
||||||
|
/// Show parsed recipe, probably not very useful.
|
||||||
|
Info {
|
||||||
|
/// The name of the recipe to show info for, eg "my_widget".
|
||||||
|
target: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
// let repo = tools::Repo::new(&args.repo).unwrap();
|
|
||||||
// repo.compile(&args.target)?;
|
|
||||||
let mut repos = tools::Repos::default();
|
let mut repos = tools::Repos::default();
|
||||||
for repo_path in &args.repo {
|
for repo_path in &args.repo {
|
||||||
repos.add_repo(repo_path)?;
|
repos.add_repo(repo_path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let build_plan = repos.compile(&args.target)?;
|
match &args.command {
|
||||||
build_plan.make_mdbook()?;
|
Commands::Mdbook { target } => {
|
||||||
|
let build_plan = repos.compile(target)?;
|
||||||
|
build_plan.make_mdbook()?;
|
||||||
|
}
|
||||||
|
Commands::Info { target } => {
|
||||||
|
let recipe = repos.get_recipe(target)?;
|
||||||
|
println!("{:#?}", recipe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,8 @@ impl<'a> BuildPlan<'a> {
|
||||||
writeln!(bom_md_file, "# Bill of materials")?;
|
writeln!(bom_md_file, "# Bill of materials")?;
|
||||||
writeln!(bom_md_file, "")?;
|
writeln!(bom_md_file, "")?;
|
||||||
|
|
||||||
|
let mut total_cost: f32 = 0.0;
|
||||||
|
|
||||||
let mut names: Vec<&String> = self.bom.keys().collect();
|
let mut names: Vec<&String> = self.bom.keys().collect();
|
||||||
names.sort();
|
names.sort();
|
||||||
for name in names {
|
for name in names {
|
||||||
|
|
@ -226,13 +228,14 @@ impl<'a> BuildPlan<'a> {
|
||||||
)))?;
|
)))?;
|
||||||
let recipe = self.repos.get_recipe(name)?;
|
let recipe = self.repos.get_recipe(name)?;
|
||||||
let unit_cost = recipe.unit_cost()?;
|
let unit_cost = recipe.unit_cost()?;
|
||||||
let total_cost = unit_cost * item.quantity.amount;
|
let item_total_cost = unit_cost * item.quantity.amount;
|
||||||
|
total_cost += item_total_cost;
|
||||||
writeln!(bom_md_file, "* {name}")?;
|
writeln!(bom_md_file, "* {name}")?;
|
||||||
writeln!(bom_md_file, " * quantity {:?}", item.quantity)?;
|
writeln!(bom_md_file, " * quantity {:?}", item.quantity)?;
|
||||||
writeln!(
|
writeln!(
|
||||||
bom_md_file,
|
bom_md_file,
|
||||||
" * cost {:.2} ({:.2} each)",
|
" * cost {:.2} ({:.2} each)",
|
||||||
total_cost, unit_cost
|
item_total_cost, unit_cost
|
||||||
)?;
|
)?;
|
||||||
writeln!(bom_md_file, " * vendors:")?;
|
writeln!(bom_md_file, " * vendors:")?;
|
||||||
match &recipe.action {
|
match &recipe.action {
|
||||||
|
|
@ -250,6 +253,9 @@ impl<'a> BuildPlan<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeln!(bom_md_file, "")?;
|
||||||
|
writeln!(bom_md_file, "Total cost: {:.2}", total_cost)?;
|
||||||
|
|
||||||
writeln!(
|
writeln!(
|
||||||
summary_md_file,
|
summary_md_file,
|
||||||
" - [Bill of Materials](overview/bom.md)"
|
" - [Bill of Materials](overview/bom.md)"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue