Skip to content

Commit

Permalink
CLI: Updates local dependency, opens editor (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
dcodesdev authored Jul 24, 2024
1 parent 67db250 commit 910c110
Show file tree
Hide file tree
Showing 8 changed files with 362 additions and 141 deletions.
340 changes: 218 additions & 122 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rustfinity"
version = "0.2.8"
version = "0.2.9"
edition = "2021"
license = "MIT"
description = "Rustfinity.com CLI"
Expand Down
53 changes: 53 additions & 0 deletions crates/cli/src/cargo_toml.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use crate::constants::GITHUB_REPO_URL;

pub fn update_dependency_if_exists(cargo_toml: &mut String) -> anyhow::Result<()> {
let mut updated_content = cargo_toml
.lines()
.map(|line| {
if line.contains("syntest") {
format!("syntest = {{ git = \"{}\" }}", GITHUB_REPO_URL)
} else {
line.to_string()
}
})
.collect::<Vec<String>>()
.join("\n");

updated_content.push_str("\n");

*cargo_toml = updated_content;

Ok(())
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_update_dependency_if_exists() {
let mut cargo_toml = r#"
[package]
name = "rustfinity"
version = "0.1.0"
[dependencies]
syntest = "1.0"
"#
.to_string();

// update existing dependency
update_dependency_if_exists(&mut cargo_toml).unwrap();

let expected = r#"
[package]
name = "rustfinity"
version = "0.1.0"
[dependencies]
syntest = { git = "https://www.github.com/dcodesdev/rustfinity.com" }
"#;

assert_eq!(cargo_toml, expected);
}
}
2 changes: 1 addition & 1 deletion crates/cli/src/challenge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ mod tests {
let slug = "two-sum";
assert_eq!(challenge_exists(slug).await.unwrap(), false);

let slug = "hello-world";
let slug = "printing-hello-world";
assert_eq!(challenge_exists(slug).await.unwrap(), true);
}
}
4 changes: 4 additions & 0 deletions crates/cli/src/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub const GITHUB_CHALLENGES_BASE_URL: &'static str =
"https://raw.githubusercontent.com/dcodesdev/rustfinity.com/main/challenges";

pub const GITHUB_REPO_URL: &'static str = "https://www.github.com/dcodesdev/rustfinity.com";
55 changes: 38 additions & 17 deletions crates/cli/src/download.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use crate::challenge::challenge_exists;
use crate::{
cargo_toml::update_dependency_if_exists, challenge::challenge_exists, constants::*,
editor::Editor,
};
use dload::Downloader;
use futures::future::join_all;
use std::fs;

const FILES: [&'static str; 4] = [
"description.md",
Expand All @@ -9,9 +13,6 @@ const FILES: [&'static str; 4] = [
"tests/tests.rs",
];

const GITHUB_BASE_URL: &'static str =
"https://raw.githubusercontent.com/dcodesdev/rustfinity.com/main/challenges";

pub async fn get_challenge(challenge: &str) -> anyhow::Result<()> {
if !challenge_exists(challenge).await? {
println!("Challenge does not exist 🥺\n\nPlease make sure you've written the challenge name correctly.");
Expand All @@ -21,20 +22,34 @@ pub async fn get_challenge(challenge: &str) -> anyhow::Result<()> {
let futures: Vec<_> = FILES
.iter()
.map(|file| {
let url = format!("{}/{}/{}", GITHUB_BASE_URL, challenge, file);
let url = format!("{}/{}/{}", GITHUB_CHALLENGES_BASE_URL, challenge, file);
let challenge = challenge.to_string();
async move { download_file(&url, &challenge).await }
})
.collect();

let results = join_all(futures).await;

// After the download, update the Cargo.toml file
// if syntest was a dependency, update it's value to
// https://github.com/dcodesdev/rustfinity.com
let file_path = format!("{}/Cargo.toml", challenge);
let mut cargo_toml = fs::read_to_string(&file_path)?;
update_dependency_if_exists(&mut cargo_toml)?;
fs::write(&file_path, &cargo_toml)?;

// Check all results are successful
if results.iter().all(Result::is_ok) {
println!(
"Challenge downloaded 🥳\n\nRun the following command to get started:\n\ncd {}",
challenge
);
// open it in the users editor
if let Some(editor) = Editor::find() {
editor.open(challenge);
} else {
println!(
"Challenge downloaded 🥳\n\nRun the following command to get started:\n\ncd {}",
challenge
);
}

Ok(())
} else {
Err(anyhow::anyhow!("One or more files failed to download"))
Expand Down Expand Up @@ -80,7 +95,7 @@ mod tests {

mod download {
const CHALLENGES: [&'static str; 7] = [
"hello-world",
"printing-hello-world",
"character-counting-string",
"mathematical-operations",
"fizz-buzz",
Expand Down Expand Up @@ -140,10 +155,13 @@ mod tests {
let temp_path = temp_dir.path();
env::set_current_dir(&temp_path).ok();

let url = "https://raw.githubusercontent.com/dcodesdev/rustfinity.com/main/challenges/hello-world/description.md";
let challenge = "hello-world";
let challenge = "printing-hello-world";
let url = format!(
"{}/{}/description.md",
GITHUB_CHALLENGES_BASE_URL, challenge
);

let result = download_file(url, challenge).await;
let result = download_file(&url, challenge).await;

assert!(result.is_ok());

Expand All @@ -158,15 +176,18 @@ mod tests {
}

#[tokio::test]
async fn test_download_file_sub_dir() {
async fn test_renames_starter() {
let temp_dir = tempdir().expect("Failed to create temp dir");
let temp_path = temp_dir.path();
env::set_current_dir(&temp_path).ok();

let url = "https://raw.githubusercontent.com/dcodesdev/rustfinity.com/main/challenges/hello-world/src/starter.rs";
let challenge = "hello-world";
let challenge = "printing-hello-world";
let url = format!(
"{}/{}/src/starter.rs",
GITHUB_CHALLENGES_BASE_URL, challenge
);

let result = download_file(url, challenge).await;
let result = download_file(&url, challenge).await;

assert!(result.is_ok());

Expand Down
44 changes: 44 additions & 0 deletions crates/cli/src/editor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use std::process::Command;

/// Editors the user might be using
#[derive(Debug, PartialEq)]
pub enum Editor {
VSCode,
Zed,
}

impl Editor {
pub fn find() -> Option<Self> {
if Command::new("code").arg("--version").output().is_ok() {
return Some(Editor::VSCode);
}

if Command::new("zed").arg("--version").output().is_ok() {
return Some(Editor::Zed);
}

None
}

pub fn open(&self, path: &str) {
Command::new(self.command()).arg(path).spawn().unwrap();
}

fn command(&self) -> &str {
match self {
Editor::VSCode => "code",
Editor::Zed => "zed",
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_find_editor() {
let editor = Editor::find();
assert_eq!(editor, None);
}
}
3 changes: 3 additions & 0 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
mod cargo_toml;
mod challenge;
mod cli;
mod constants;
mod crates_io;
mod download;
mod editor;

use clap::Parser;
use cli::{run, Cli};
Expand Down

0 comments on commit 910c110

Please sign in to comment.