Skip to content

Commit e08e272

Browse files
author
Chris
committed
update processes & add install script
1 parent a0f7127 commit e08e272

5 files changed

Lines changed: 181 additions & 1 deletion

File tree

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@ A command-line tool for interacting with the [Canine](https://canine.sh) platfor
44

55
## Installation
66

7+
```bash
8+
curl -sSL https://raw.githubusercontent.com/CanineHQ/cli/main/install.sh | sh
9+
```
10+
11+
### macOS (Homebrew)
12+
13+
```bash
14+
brew tap CanineHQ/canine
15+
brew install canine
16+
```
17+
18+
### From source
19+
720
```bash
821
cargo install --path .
922
```

install.sh

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#!/bin/sh
2+
set -e
3+
4+
REPO="CanineHQ/cli"
5+
BINARY_NAME="k9"
6+
INSTALL_DIR="/usr/local/bin"
7+
8+
main() {
9+
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
10+
ARCH=$(uname -m)
11+
12+
case "$OS" in
13+
darwin*)
14+
echo "macOS detected."
15+
echo ""
16+
echo "Install Canine CLI using Homebrew:"
17+
echo ""
18+
echo " brew tap CanineHQ/canine"
19+
echo " brew install canine"
20+
echo ""
21+
exit 0
22+
;;
23+
linux*)
24+
install_linux
25+
;;
26+
mingw*|msys*|cygwin*|windows*)
27+
echo "Error: Windows is not supported."
28+
echo "Please use WSL (Windows Subsystem for Linux) and run this script again."
29+
exit 1
30+
;;
31+
*)
32+
echo "Error: Unsupported operating system: $OS"
33+
exit 1
34+
;;
35+
esac
36+
}
37+
38+
install_linux() {
39+
echo "Linux detected."
40+
41+
# Detect architecture
42+
case "$ARCH" in
43+
x86_64|amd64)
44+
ARCH="amd64"
45+
;;
46+
aarch64|arm64)
47+
ARCH="arm64"
48+
;;
49+
*)
50+
echo "Error: Unsupported architecture: $ARCH"
51+
exit 1
52+
;;
53+
esac
54+
55+
echo "Architecture: $ARCH"
56+
57+
# Get latest release version
58+
echo "Fetching latest release..."
59+
LATEST_VERSION=$(curl -sL "https://api.github.com/repos/${REPO}/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
60+
61+
if [ -z "$LATEST_VERSION" ]; then
62+
echo "Error: Could not determine latest version."
63+
exit 1
64+
fi
65+
66+
echo "Latest version: $LATEST_VERSION"
67+
68+
# Construct download URL
69+
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${LATEST_VERSION}/${BINARY_NAME}-linux-${ARCH}"
70+
71+
echo "Downloading from: $DOWNLOAD_URL"
72+
73+
# Create temp directory
74+
TMP_DIR=$(mktemp -d)
75+
trap "rm -rf $TMP_DIR" EXIT
76+
77+
# Download binary
78+
curl -sL "$DOWNLOAD_URL" -o "$TMP_DIR/$BINARY_NAME"
79+
80+
# Make executable
81+
chmod +x "$TMP_DIR/$BINARY_NAME"
82+
83+
# Install to /usr/local/bin (may require sudo)
84+
echo "Installing to $INSTALL_DIR/$BINARY_NAME..."
85+
if [ -w "$INSTALL_DIR" ]; then
86+
mv "$TMP_DIR/$BINARY_NAME" "$INSTALL_DIR/$BINARY_NAME"
87+
else
88+
sudo mv "$TMP_DIR/$BINARY_NAME" "$INSTALL_DIR/$BINARY_NAME"
89+
fi
90+
91+
echo ""
92+
echo "Canine CLI installed successfully!"
93+
echo "Run 'k9 --help' to get started."
94+
}
95+
96+
main

src/cli.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ pub enum ProjectAction {
131131

132132
/// List processes for a project
133133
Processes(ProjectId),
134+
135+
/// Get logs for a process
136+
Logs(ProjectLogs),
134137
}
135138

136139
#[derive(Args, Debug)]
@@ -149,6 +152,19 @@ pub struct ProjectRun {
149152
pub command: Vec<String>,
150153
}
151154

155+
#[derive(Args, Debug)]
156+
pub struct ProjectLogs {
157+
#[arg(long)]
158+
pub project: String,
159+
160+
#[arg(long)]
161+
pub process: String,
162+
163+
/// Follow log output
164+
#[arg(long, default_value_t = false)]
165+
pub tail: bool,
166+
}
167+
152168
#[derive(Args, Debug)]
153169
pub struct DeployProjectParams {
154170
#[arg(long)]

src/commands/project.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::time::Duration;
66
use colored::Colorize;
77
use tabled::Table;
88

9-
use crate::cli::{DeployProjectParams, ProjectId, ProjectRun};
9+
use crate::cli::{DeployProjectParams, ProjectId, ProjectLogs, ProjectRun};
1010
use crate::client::{CanineClient, CanineError, Pod, ProcessStatus};
1111
use crate::config::CanineConfig;
1212
use crate::kubeconfig::{ensure_kubectl, kubeconfig_to_yaml};
@@ -80,6 +80,58 @@ pub async fn handle_run(
8080
Ok(())
8181
}
8282

83+
pub async fn handle_logs(
84+
config: &CanineConfig,
85+
client: &CanineClient,
86+
params: &ProjectLogs,
87+
) -> Result<(), Box<dyn std::error::Error>> {
88+
gate_kubectl();
89+
90+
print!("Fetching project {}... ", params.project.cyan());
91+
io::stdout().flush().unwrap();
92+
let project = client.get_project(&params.project).await?;
93+
println!("{}", "done".green());
94+
95+
print!(
96+
"Downloading kubeconfig for cluster {}... ",
97+
project.cluster_name.cyan()
98+
);
99+
io::stdout().flush().unwrap();
100+
let kubeconfig = client
101+
.download_kubeconfig_file(&project.cluster_name.to_string())
102+
.await?;
103+
let yaml = kubeconfig_to_yaml(&kubeconfig.kubeconfig)?;
104+
config.save_kubeconfig(yaml)?;
105+
println!("{}", "done".green());
106+
107+
print!("Finding process {}... ", params.process.cyan());
108+
io::stdout().flush().unwrap();
109+
let processes = client.get_processes(&params.project).await?;
110+
let pod = processes
111+
.pods
112+
.iter()
113+
.find(|p| p.name.contains(&params.process))
114+
.ok_or_else(|| format!("Process '{}' not found", params.process))?;
115+
println!("{}", "done".green());
116+
117+
let mut args = vec!["logs", "-n", &pod.namespace, &pod.name];
118+
if params.tail {
119+
args.push("-f");
120+
}
121+
122+
Command::new("kubectl")
123+
.args(&args)
124+
.env(
125+
"KUBECONFIG",
126+
CanineConfig::credential_path().to_str().unwrap(),
127+
)
128+
.stdout(Stdio::inherit())
129+
.stderr(Stdio::inherit())
130+
.status()?;
131+
132+
Ok(())
133+
}
134+
83135
pub async fn handle_deploy(
84136
client: &CanineClient,
85137
params: &DeployProjectParams,

src/main.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
8686
ProjectAction::Deploy(params) => {
8787
commands::project::handle_deploy(&client, &params).await?;
8888
}
89+
ProjectAction::Logs(params) => {
90+
commands::project::handle_logs(&config, &client, &params).await?;
91+
}
8992
},
9093
Namespace::Builds(cmd) => match cmd.action {
9194
BuildAction::List(list) => {

0 commit comments

Comments
 (0)