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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "zoo"
version = "0.2.180"
edition = "2021"
edition = "2024"
rust-version = "1.95"
build = "build.rs"

Expand Down
2 changes: 1 addition & 1 deletion rustfmt.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
max_width = 120
edition = "2018"
edition = "2024"
format_code_in_doc_comments = true
format_strings = false
imports_granularity = "Crate"
Expand Down
2 changes: 1 addition & 1 deletion src/cmd_alias.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::io::Write;

use anyhow::{bail, Result};
use anyhow::{Result, bail};
use clap::{Command, CommandFactory, Parser};

/// Create command shortcuts.
Expand Down
2 changes: 1 addition & 1 deletion src/cmd_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{
io::{Read, Write},
};

use anyhow::{anyhow, Result};
use anyhow::{Result, anyhow};
use clap::Parser;
use reqwest::header::CONTENT_TYPE;
use serde::{Deserialize, Serialize};
Expand Down
42 changes: 21 additions & 21 deletions src/cmd_api_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,30 +67,30 @@ impl crate::cmd::Command for CmdApiCallStatus {
updated_at: _,
user_id: _,
} = &api_call
&& *status == kittycad::types::ApiCallStatus::Completed
&& let Some(outputs) = &outputs
{
if *status == kittycad::types::ApiCallStatus::Completed {
if let Some(outputs) = &outputs {
let path = std::env::current_dir()?;
for (name, output) in outputs {
if output.is_empty() {
anyhow::bail!("no output was generated for the file conversion! (this is probably a bug in the API) you should report it to support@zoo.dev");
}
let path = path.join(name);
std::fs::write(&path, &output.0)?;
}

let paths = outputs
.keys()
.map(|k| path.join(k))
.map(|p| p.to_string_lossy().to_string())
.collect_vec();
// Tell them where we saved the file.
writeln!(ctx.io.out, "Saved file conversion output(s) to: {}", paths.join(", "))?;

// Return early.
return Ok(());
let path = std::env::current_dir()?;
for (name, output) in outputs {
if output.is_empty() {
anyhow::bail!(
"no output was generated for the file conversion! (this is probably a bug in the API) you should report it to support@zoo.dev"
);
}
let path = path.join(name);
std::fs::write(&path, &output.0)?;
}

let paths = outputs
.keys()
.map(|k| path.join(k))
.map(|p| p.to_string_lossy().to_string())
.collect_vec();
// Tell them where we saved the file.
writeln!(ctx.io.out, "Saved file conversion output(s) to: {}", paths.join(", "))?;

// Return early.
return Ok(());
}

// Print the output of the conversion.
Expand Down
10 changes: 5 additions & 5 deletions src/cmd_auth.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::HashMap;

use anyhow::{anyhow, Result};
use anyhow::{Result, anyhow};
use clap::Parser;
use oauth2::TokenResponse;

Expand Down Expand Up @@ -437,10 +437,10 @@ impl crate::cmd::Command for CmdAuthStatus {

let only_host = ctx.global_host().map(|s| s.to_string());
for hostname in &hostnames {
if let Some(h) = only_host.as_deref() {
if h != *hostname {
continue;
}
if let Some(h) = only_host.as_deref()
&& h != *hostname
{
continue;
}

hostname_found = true;
Expand Down
2 changes: 1 addition & 1 deletion src/cmd_completion.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use anyhow::Result;
use clap::{Command, CommandFactory, Parser};
use clap_complete::{generate, Shell};
use clap_complete::{Shell, generate};

/// Generate shell completion scripts.
///
Expand Down
4 changes: 2 additions & 2 deletions src/cmd_config.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::{bail, Result};
use anyhow::{Result, bail};
use clap::Parser;

use crate::config::{ConfigOption, CONFIG_OPTIONS};
use crate::config::{CONFIG_OPTIONS, ConfigOption};

// TODO: make this doc a function that parses from the config the options so it's not hardcoded
/// Manage configuration for `zoo`.
Expand Down
112 changes: 58 additions & 54 deletions src/cmd_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use anyhow::Result;
use base64::prelude::*;
use clap::Parser;
use kittycad_modeling_cmds::{
self as kcmc, ok_response::OkModelingCmdResponse, shared::FileImportFormat, websocket::OkWebSocketResponseData,
ModelingCmd,
self as kcmc, ModelingCmd, ok_response::OkModelingCmdResponse, shared::FileImportFormat,
websocket::OkWebSocketResponseData,
};

use crate::cmd_kcl::write_deterministic_export;
Expand Down Expand Up @@ -145,7 +145,9 @@ impl crate::cmd::Command for CmdFileConvert {
)?;
}
} else {
anyhow::bail!("no output was generated! (this is probably a bug in the API) you should report it to support@zoo.dev");
anyhow::bail!(
"no output was generated! (this is probably a bug in the API) you should report it to support@zoo.dev"
);
}
}

Expand Down Expand Up @@ -197,13 +199,14 @@ pub struct CmdFileSnapshot {
impl crate::cmd::Command for CmdFileSnapshot {
async fn run(&self, ctx: &mut crate::context::Context) -> Result<()> {
// Make sure the parent directory is a directory and exists.
if let Some(parent) = self.output_file.parent() {
if !parent.is_dir() && !parent.to_str().unwrap_or("").is_empty() {
anyhow::bail!(
"directory `{}` does not exist or is not a directory",
parent.to_str().unwrap_or("")
);
}
if let Some(parent) = self.output_file.parent()
&& !parent.is_dir()
&& !parent.to_str().unwrap_or("").is_empty()
{
anyhow::bail!(
"directory `{}` does not exist or is not a directory",
parent.to_str().unwrap_or("")
);
}

// Parse the image format.
Expand Down Expand Up @@ -233,51 +236,52 @@ impl crate::cmd::Command for CmdFileSnapshot {
// In order for the program to know it's dealing with this type, an
// attempt to parse as json is made, then we check for the buffers
// property which describes what external files are needed.
let mut files: Vec<kcmc::ImportFile> = vec![kcmc::ImportFile::builder()
.path(filename.to_string())
.data(input.clone())
.build()];

if matches!(src_format, kcmc::format::InputFormat3d::Gltf(_)) {
if let Ok(str) = std::str::from_utf8(&input) {
if let Ok(json) = serde_json::from_str::<crate::types::GltfStandardJsonLite>(str) {
// Use the path of the control file as the prefix path of
// the relative file name.

for buffer in json.buffers {
if is_data_uri(&buffer.uri) {
// Using the whole data URI would create massive
// path properties. Use a hash instead.
let mut hasher = DefaultHasher::new();
buffer.uri.hash(&mut hasher);
let hash_u64 = hasher.finish();

if let Some(buf_base64) = buffer.uri.split(',').nth(1) {
files.push(
kcmc::ImportFile::builder()
.path(hash_u64.to_string())
.data(BASE64_STANDARD.decode(buf_base64)?)
.build(),
);
} else {
anyhow::bail!("invalid data uri in gltf.buffers.uri property");
}
} else {
let path_ = self
.input
.parent()
.unwrap_or(std::path::Path::new(""))
.join(std::path::Path::new(&buffer.uri));
let path = path_.to_str().unwrap_or_default();
let data = ctx.read_file(path)?;
files.push(
kcmc::ImportFile::builder()
.path(path_.file_name().unwrap_or_default().to_str().unwrap_or("").to_string())
.data(data)
.build(),
);
}
let mut files: Vec<kcmc::ImportFile> = vec![
kcmc::ImportFile::builder()
.path(filename.to_string())
.data(input.clone())
.build(),
];

if matches!(src_format, kcmc::format::InputFormat3d::Gltf(_))
&& let Ok(str) = std::str::from_utf8(&input)
&& let Ok(json) = serde_json::from_str::<crate::types::GltfStandardJsonLite>(str)
{
// Use the path of the control file as the prefix path of
// the relative file name.

for buffer in json.buffers {
if is_data_uri(&buffer.uri) {
// Using the whole data URI would create massive
// path properties. Use a hash instead.
let mut hasher = DefaultHasher::new();
buffer.uri.hash(&mut hasher);
let hash_u64 = hasher.finish();

if let Some(buf_base64) = buffer.uri.split(',').nth(1) {
files.push(
kcmc::ImportFile::builder()
.path(hash_u64.to_string())
.data(BASE64_STANDARD.decode(buf_base64)?)
.build(),
);
} else {
anyhow::bail!("invalid data uri in gltf.buffers.uri property");
}
} else {
let path_ = self
.input
.parent()
.unwrap_or(std::path::Path::new(""))
.join(std::path::Path::new(&buffer.uri));
let path = path_.to_str().unwrap_or_default();
let data = ctx.read_file(path)?;
files.push(
kcmc::ImportFile::builder()
.path(path_.file_name().unwrap_or_default().to_str().unwrap_or("").to_string())
.data(data)
.build(),
);
}
}
}
Expand Down
29 changes: 16 additions & 13 deletions src/cmd_kcl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{net::SocketAddr, path::Path, str::FromStr};
use anyhow::Result;
use clap::Parser;
use image::{DynamicImage, ImageReader};
use kcl_lib::{unit_conversion::ToKcmc, ToLspRange, TypedPath};
use kcl_lib::{ToLspRange, TypedPath, unit_conversion::ToKcmc};
use kcmc::{format::OutputFormat3d as OutputFormat, ok_response::OkModelingCmdResponse};
use kittycad::types as kt;
use kittycad_modeling_cmds::{self as kcmc, units::UnitLength, websocket::ModelingSessionData};
Expand Down Expand Up @@ -351,13 +351,14 @@ pub struct CmdKclSnapshot {
impl crate::cmd::Command for CmdKclSnapshot {
async fn run(&self, ctx: &mut crate::context::Context) -> Result<()> {
// Make sure the parent directory is a directory and exists.
if let Some(parent) = self.output_file.parent() {
if !parent.is_dir() && !parent.to_str().unwrap_or("").is_empty() {
anyhow::bail!(
"directory `{}` does not exist or is not a directory",
parent.to_str().unwrap_or("")
);
}
if let Some(parent) = self.output_file.parent()
&& !parent.is_dir()
&& !parent.to_str().unwrap_or("").is_empty()
{
anyhow::bail!(
"directory `{}` does not exist or is not a directory",
parent.to_str().unwrap_or("")
);
}

// Parse the image format.
Expand Down Expand Up @@ -765,8 +766,8 @@ pub fn get_image_format_from_extension_kcmc(ext: &str) -> Result<kcmc::ImageForm
Ok(format) => Ok(format),
Err(_) => {
anyhow::bail!(
"unknown source format for file extension: {ext}. Try setting the `--src-format` flag explicitly or use a valid format."
)
"unknown source format for file extension: {ext}. Try setting the `--src-format` flag explicitly or use a valid format."
)
}
}
}
Expand All @@ -777,8 +778,8 @@ pub fn get_image_format_from_extension_dot_rs(ext: &str) -> Result<kittycad::typ
Ok(format) => Ok(format),
Err(_) => {
anyhow::bail!(
"unknown source format for file extension: {ext}. Try setting the `--src-format` flag explicitly or use a valid format."
)
"unknown source format for file extension: {ext}. Try setting the `--src-format` flag explicitly or use a valid format."
)
}
}
}
Expand Down Expand Up @@ -1757,7 +1758,9 @@ fn print_trace_link(io: &mut IoStreams, session_data: &Option<ModelingSessionDat
return;
};
let api_call_id = &data.api_call_id;
let link = format!("https://ui.honeycomb.io/kittycad/environments/prod/datasets/api-deux?query=%7B%22time_range%22%3A7200%2C%22granularity%22%3A0%2C%22calculations%22%3A%5B%7B%22op%22%3A%22COUNT%22%7D%5D%2C%22filters%22%3A%5B%7B%22column%22%3A%22api_call.id%22%2C%22op%22%3A%22%3D%22%2C%22value%22%3A%22{api_call_id}%22%7D%5D%2C%22filter_combination%22%3A%22AND%22%2C%22limit%22%3A1000%7D");
let link = format!(
"https://ui.honeycomb.io/kittycad/environments/prod/datasets/api-deux?query=%7B%22time_range%22%3A7200%2C%22granularity%22%3A0%2C%22calculations%22%3A%5B%7B%22op%22%3A%22COUNT%22%7D%5D%2C%22filters%22%3A%5B%7B%22column%22%3A%22api_call.id%22%2C%22op%22%3A%22%3D%22%2C%22value%22%3A%22{api_call_id}%22%7D%5D%2C%22filter_combination%22%3A%22AND%22%2C%22limit%22%3A1000%7D"
);
let _ = writeln!(
io.out,
"Was this request slow? Send a Zoo employee this link:\n----\n{link}"
Expand Down
18 changes: 10 additions & 8 deletions src/cmd_ml/cmd_text_to_cad.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use anyhow::Result;
use clap::{Parser, ValueEnum};
use kcmc::{
each_cmd as mcmd, format::InputFormat3d, ok_response::OkModelingCmdResponse, websocket::OkWebSocketResponseData,
ImageFormat, ModelingCmd,
ImageFormat, ModelingCmd, each_cmd as mcmd, format::InputFormat3d, ok_response::OkModelingCmdResponse,
websocket::OkWebSocketResponseData,
};
use kittycad_modeling_cmds::{self as kcmc, ImportFile};

Expand Down Expand Up @@ -131,8 +131,8 @@ impl crate::cmd::Command for CmdTextToCadExport {
}
} else {
anyhow::bail!(
"no output was generated! (this is probably a bug in the API) you should report it to support@zoo.dev"
);
"no output was generated! (this is probably a bug in the API) you should report it to support@zoo.dev"
);
}
} else if let Some(code) = &model.code {
let filename = prompt.replace(" ", "_").to_lowercase() + ".kcl";
Expand Down Expand Up @@ -363,10 +363,12 @@ async fn get_image_bytes(
kcl_lib::SourceRange::default(),
&ModelingCmd::from(
mcmd::ImportFiles::builder()
.files(vec![ImportFile::builder()
.path("model.gltf".to_string())
.data(gltf_bytes.to_vec())
.build()])
.files(vec![
ImportFile::builder()
.path("model.gltf".to_string())
.data(gltf_bytes.to_vec())
.build(),
])
.format(InputFormat3d::Gltf(Default::default()))
.build(),
),
Expand Down
9 changes: 5 additions & 4 deletions src/cmd_org.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1439,10 +1439,11 @@ fn is_supported_dataset_file(path: &Path) -> bool {
return false;
};
let mut lower = file_name.to_ascii_lowercase();
if let Some((stem, suffix)) = lower.rsplit_once('.') {
if !suffix.is_empty() && suffix.chars().all(|c| c.is_ascii_digit()) {
lower = stem.to_string();
}
if let Some((stem, suffix)) = lower.rsplit_once('.')
&& !suffix.is_empty()
&& suffix.chars().all(|c| c.is_ascii_digit())
{
lower = stem.to_string();
}
let Some((_, extension)) = lower.rsplit_once('.') else {
return false;
Expand Down
Loading
Loading