From e9bc7970a26bbef7581a5787221683ab060a332f Mon Sep 17 00:00:00 2001 From: ea-open-source Date: Thu, 26 May 2022 17:14:36 +0700 Subject: [PATCH 1/3] Add subcommand login, read token from user --- Cargo.lock | 21 +++++-- language/tools/move-cli/Cargo.toml | 1 + language/tools/move-cli/src/lib.rs | 4 ++ language/tools/move-cli/src/login/cli.rs | 55 +++++++++++++++++++ language/tools/move-cli/src/login/mod.rs | 1 + language/tools/move-cli/src/package/cli.rs | 9 +-- .../src/source_package/manifest_parser.rs | 1 + 7 files changed, 80 insertions(+), 12 deletions(-) create mode 100644 language/tools/move-cli/src/login/cli.rs create mode 100644 language/tools/move-cli/src/login/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 70b2053a3c..ebe9d45fdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -529,9 +529,9 @@ dependencies = [ [[package]] name = "combine" -version = "4.6.2" +version = "4.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b2f5d0ee456f3928812dfc8c6d9a1d592b98678f6d56db9b0cd2b7bc6c8db5" +checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" dependencies = [ "bytes", "memchr", @@ -1466,7 +1466,7 @@ dependencies = [ "strip-ansi-escapes", "target-spec", "toml", - "toml_edit", + "toml_edit 0.10.1", "twox-hash", ] @@ -2156,6 +2156,7 @@ dependencies = [ "serde 1.0.130", "serde_yaml", "tempfile", + "toml_edit 0.14.4", "walkdir", "workspace-hack", ] @@ -4778,6 +4779,18 @@ dependencies = [ "kstring", ] +[[package]] +name = "toml_edit" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5376256e44f2443f8896ac012507c19a012df0fe8758b55246ae51a2279db51f" +dependencies = [ + "combine", + "indexmap", + "itertools 0.10.1", + "serde 1.0.130", +] + [[package]] name = "tracing" version = "0.1.26" @@ -4868,7 +4881,7 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "static_assertions", ] diff --git a/language/tools/move-cli/Cargo.toml b/language/tools/move-cli/Cargo.toml index f9f50ede34..9148670157 100644 --- a/language/tools/move-cli/Cargo.toml +++ b/language/tools/move-cli/Cargo.toml @@ -22,6 +22,7 @@ tempfile = "3.2.0" walkdir = "2.3.1" codespan-reporting = "0.11.1" itertools = "0.10.0" +toml_edit = { version = "0.14.3", features = ["easy"] } bcs = "0.1.2" move-bytecode-verifier = { path = "../../move-bytecode-verifier" } diff --git a/language/tools/move-cli/src/lib.rs b/language/tools/move-cli/src/lib.rs index 1e0d763187..5cf8cc275a 100644 --- a/language/tools/move-cli/src/lib.rs +++ b/language/tools/move-cli/src/lib.rs @@ -7,6 +7,7 @@ pub mod base; pub mod experimental; pub mod package; pub mod sandbox; +mod login; /// Default directory where saved Move resources live pub const DEFAULT_STORAGE_DIR: &str = "storage"; @@ -95,6 +96,8 @@ pub enum Command { #[clap(subcommand)] cmd: experimental::cli::ExperimentalCommand, }, + #[clap(name = "login")] + Login, } pub fn run_cli( @@ -119,6 +122,7 @@ pub fn run_cli( cmd, natives, ), + Command::Login => login::cli::handle_login_commands(), } } diff --git a/language/tools/move-cli/src/login/cli.rs b/language/tools/move-cli/src/login/cli.rs new file mode 100644 index 0000000000..3832317d03 --- /dev/null +++ b/language/tools/move-cli/src/login/cli.rs @@ -0,0 +1,55 @@ +use std::collections::HashMap; +use std::io; +use std::fs::File; +use std::path::PathBuf; +use anyhow::{bail, Result}; +use toml_edit::easy::{Value}; +use toml_edit::easy::map::Map; + +pub fn handle_login_commands() -> Result<()> { + let url: &str; + if cfg!(debug_assertions) { + url = "https://movey-app-staging.herokuapp.com"; + } else { + url = "https://movey.net"; + } + println!("please paste the API Token found on {}/settings/tokens below", url); + let mut line = String::new(); + match io::stdin().read_line(&mut line) { + Ok(_) => { + if let Some('\n') = line.chars().next_back() { + line.pop(); + } + if let Some('\r') = line.chars().next_back() { + line.pop(); + } + print!("{}", line); + } + Err(err) => { + bail!("Error reading input: {}", err); + } + } + save_credential(line) +} + +fn save_credential(token: String) -> Result<()> { + let move_home = std::env::var("MOVE_HOME").unwrap_or_else(|_| { + format!( + "{}/.move", + std::env::var("HOME").expect("env var 'HOME' must be set") + ) + }); + let credential_path = move_home + "/credential.json"; + let credential_file = PathBuf::from(credential_path.clone()); + if !credential_file.exists() { + File::create(credential_path)?; + } + let mut value = Map::new(); + value.insert(String::from("token"), Value::String(token)); + let mut toml = Value::Table(Map::new()); + toml.as_table_mut().unwrap().insert(String::from("registry"), Value::Table(value)); + + let contents = toml.to_string(); + println!("{}", contents); + Ok(()) +} diff --git a/language/tools/move-cli/src/login/mod.rs b/language/tools/move-cli/src/login/mod.rs new file mode 100644 index 0000000000..4f773726a2 --- /dev/null +++ b/language/tools/move-cli/src/login/mod.rs @@ -0,0 +1 @@ +pub mod cli; diff --git a/language/tools/move-cli/src/package/cli.rs b/language/tools/move-cli/src/package/cli.rs index 642aad67e0..7b3f8c5136 100644 --- a/language/tools/move-cli/src/package/cli.rs +++ b/language/tools/move-cli/src/package/cli.rs @@ -1,14 +1,7 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use std::{ - collections::HashMap, - fmt, - fs::{create_dir_all, read_to_string}, - io::Write, - path::{Path, PathBuf}, - process::ExitStatus, -}; +use std::{collections::HashMap, fmt, fs::{create_dir_all, read_to_string}, io::Write, path::{Path, PathBuf}, process::ExitStatus}; // if windows #[cfg(target_family = "windows")] diff --git a/language/tools/move-package/src/source_package/manifest_parser.rs b/language/tools/move-package/src/source_package/manifest_parser.rs index 428b7c949b..19acbbe473 100644 --- a/language/tools/move-package/src/source_package/manifest_parser.rs +++ b/language/tools/move-package/src/source_package/manifest_parser.rs @@ -321,6 +321,7 @@ fn parse_dependency(tval: TV) -> Result { } (None, Some(git)) => { // Look to see if a MOVE_HOME has been set. Otherwise default to $HOME + // let a = std::env::var("MOVE_HOME").unwrap(); let move_home = std::env::var("MOVE_HOME").unwrap_or_else(|_| { format!( "{}/.move", From 28db79a9217707ff0c8e92814ad7e18d7a8d9de4 Mon Sep 17 00:00:00 2001 From: ea-open-source Date: Fri, 27 May 2022 18:00:42 +0700 Subject: [PATCH 2/3] Store token to file, add unit tests --- Cargo.lock | 10 ++ language/tools/move-cli/Cargo.toml | 1 + language/tools/move-cli/src/lib.rs | 2 +- language/tools/move-cli/src/login/cli.rs | 159 ++++++++++++++++++--- language/tools/move-cli/tests/cli_tests.rs | 76 ++++++++++ 5 files changed, 230 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ebe9d45fdc..7305ec44ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1536,6 +1536,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "home" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" +dependencies = [ + "winapi", +] + [[package]] name = "humansize" version = "1.1.0" @@ -2127,6 +2136,7 @@ dependencies = [ "colored", "datatest-stable", "difference", + "home", "include_dir", "itertools 0.10.1", "move-binary-format", diff --git a/language/tools/move-cli/Cargo.toml b/language/tools/move-cli/Cargo.toml index 9148670157..d658ba65e4 100644 --- a/language/tools/move-cli/Cargo.toml +++ b/language/tools/move-cli/Cargo.toml @@ -53,6 +53,7 @@ workspace-hack = { version = "0.1", path = "../../../crates/workspace-hack" } [dev-dependencies] datatest-stable = "0.1.1" +home = "0.5.3" [[bin]] name = "move" diff --git a/language/tools/move-cli/src/lib.rs b/language/tools/move-cli/src/lib.rs index 5cf8cc275a..528c2c0ef5 100644 --- a/language/tools/move-cli/src/lib.rs +++ b/language/tools/move-cli/src/lib.rs @@ -122,7 +122,7 @@ pub fn run_cli( cmd, natives, ), - Command::Login => login::cli::handle_login_commands(), + Command::Login => login::cli::handle_login_commands(move_args.build_config.clone()), } } diff --git a/language/tools/move-cli/src/login/cli.rs b/language/tools/move-cli/src/login/cli.rs index 3832317d03..c49227fc33 100644 --- a/language/tools/move-cli/src/login/cli.rs +++ b/language/tools/move-cli/src/login/cli.rs @@ -1,12 +1,11 @@ -use std::collections::HashMap; -use std::io; +use std::{fs, io}; use std::fs::File; use std::path::PathBuf; use anyhow::{bail, Result}; -use toml_edit::easy::{Value}; +use toml_edit::easy::Value; use toml_edit::easy::map::Map; -pub fn handle_login_commands() -> Result<()> { +pub fn handle_login_commands(config: move_package::BuildConfig) -> Result<()> { let url: &str; if cfg!(debug_assertions) { url = "https://movey-app-staging.herokuapp.com"; @@ -26,30 +25,156 @@ pub fn handle_login_commands() -> Result<()> { print!("{}", line); } Err(err) => { - bail!("Error reading input: {}", err); + bail!("Error reading file: {}", err); } } - save_credential(line) + save_credential(line, config.test_mode) } -fn save_credential(token: String) -> Result<()> { - let move_home = std::env::var("MOVE_HOME").unwrap_or_else(|_| { +pub fn save_credential(token: String, is_test_mode: bool) -> Result<()> { + let mut move_home = std::env::var("MOVE_HOME").unwrap_or_else(|_| { format!( "{}/.move", std::env::var("HOME").expect("env var 'HOME' must be set") ) }); - let credential_path = move_home + "/credential.json"; - let credential_file = PathBuf::from(credential_path.clone()); + if is_test_mode { + move_home.push_str("/test") + } + fs::create_dir_all(&move_home)?; + let credential_path = move_home + "/credential.toml"; + let credential_file = PathBuf::from(&credential_path.clone()); if !credential_file.exists() { - File::create(credential_path)?; + File::create(&credential_path)?; + } + + let old_contents: String; + match fs::read_to_string(&credential_path) { + Ok(contents) => { + old_contents = contents; + }, + Err(error) => bail!("Error reading input: {}", error), } - let mut value = Map::new(); - value.insert(String::from("token"), Value::String(token)); - let mut toml = Value::Table(Map::new()); - toml.as_table_mut().unwrap().insert(String::from("registry"), Value::Table(value)); + let mut toml: Value = old_contents.parse() + .map_err(|e| anyhow::Error::from(e).context("could not parse input as TOML"))?; + + if let Some(registry) = toml.as_table_mut().unwrap().get_mut("registry") { + if let Some(toml_token) = registry.as_table_mut().unwrap().get_mut("token") { + *toml_token = Value::String(token); + } else { + registry.as_table_mut().unwrap() + .insert(String::from("token"), Value::String(token)); + } + } else { + let mut value = Map::new(); + value.insert(String::from("token"), Value::String(token)); + toml.as_table_mut().unwrap().insert(String::from("registry"), Value::Table(value)); + } + + let new_contents = toml.to_string(); + fs::write(credential_file, new_contents).expect("Unable to write file"); + let file = File::open(&credential_path)?; + set_permissions(&file, 0o600)?; + Ok(()) +} + +#[cfg(unix)] +fn set_permissions(file: &File, mode: u32) -> Result<()> { + use std::os::unix::fs::PermissionsExt; + + let mut perms = file.metadata()?.permissions(); + perms.set_mode(mode); + file.set_permissions(perms)?; + Ok(()) +} - let contents = toml.to_string(); - println!("{}", contents); +#[cfg(not(unix))] +#[allow(unused)] +fn set_permissions(file: &File, mode: u32) -> Result<()> { Ok(()) } + +#[cfg(test)] +mod tests { + use std::env; + use home::home_dir; + use super::*; + + fn setup_home_path() -> String { + let move_home = env::var("MOVE_HOME").unwrap_or_else(|_| { + env::var("HOME").unwrap_or_else(|_| { + let home_dir = home_dir().unwrap().to_string_lossy().to_string(); + env::set_var("HOME", &home_dir); + home_dir + }) + }); + let credential_file = move_home + "/.move/test/credential.toml"; + return credential_file; + } + + #[test] + fn save_credential_works_if_no_credential_file_exists() { + let credential_file = setup_home_path(); + let _ = fs::remove_file(&credential_file); + + save_credential(String::from("test_token"), true).unwrap(); + + let contents = fs::read_to_string(&credential_file).expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); + let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); + assert!(token.to_string().contains("test_token")); + } + + #[test] + fn save_credential_works_if_credential_file_is_empty() { + let credential_file = setup_home_path(); + + let _ = fs::remove_file(&credential_file); + File::create(&credential_file).unwrap(); + + save_credential(String::from("test_token"), true).unwrap(); + + let contents = fs::read_to_string(&credential_file).expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); + let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); + assert!(token.to_string().contains("test_token")); + } + + #[test] + fn save_credential_works_with_old_token_field() { + let credential_file = setup_home_path(); + File::create(&credential_file).unwrap(); + + let old_content = String::from("[registry]\ntoken = \"old_test_token\"\n"); + fs::write(&credential_file, old_content).expect("Unable to write file"); + + save_credential(String::from("test_token"), true).unwrap(); + + let contents = fs::read_to_string(&credential_file).expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); + let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); + assert!(token.to_string().contains("test_token")); + assert!(!token.to_string().contains("old_test_token")); + } + + #[test] + fn save_credential_works_with_old_empty_token_field() { + let credential_file = setup_home_path(); + File::create(&credential_file).unwrap(); + + let old_content = String::from("[registry]\ntoken = \"\"\n"); + fs::write(&credential_file, old_content).expect("Unable to write file"); + + save_credential(String::from("test_token"), true).unwrap(); + + let contents = fs::read_to_string(&credential_file).expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); + let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); + assert!(token.to_string().contains("test_token")); + assert!(!token.to_string().contains("old_test_token")); + } +} \ No newline at end of file diff --git a/language/tools/move-cli/tests/cli_tests.rs b/language/tools/move-cli/tests/cli_tests.rs index 5b82ce391f..164a62d152 100644 --- a/language/tools/move-cli/tests/cli_tests.rs +++ b/language/tools/move-cli/tests/cli_tests.rs @@ -1,9 +1,16 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 +use std::{env, fs}; +use std::fs::File; +use std::io::{BufRead, BufReader, Write}; use move_cli::sandbox::commands::test; use std::path::PathBuf; +use std::process::Stdio; +use home::home_dir; +use toml_edit::easy::Value; +use std::os::unix::fs::PermissionsExt; pub const CLI_METATEST_PATH: [&str; 3] = ["tests", "metatests", "args.txt"]; @@ -58,3 +65,72 @@ fn cross_process_locking_git_deps() { .expect("Package2 failed"); handle.join().unwrap(); } + +#[test] +fn save_credential_works() { + #[cfg(debug_assertions)] + const CLI_EXE: &str = "../../../target/debug/move"; + #[cfg(not(debug_assertions))] + const CLI_EXE: &str = "../../../target/release/move"; + let home = home_dir().unwrap().to_string_lossy().to_string() + "/.move/test"; + env::set_var("MOVE_HOME", &home); + match std::process::Command::new(CLI_EXE) + .current_dir(".") + .args(["login"]) + .stdin(Stdio::piped()).spawn() { + Ok(mut child) => { + let token = "test_token"; + child.stdin.as_ref().unwrap().write(token.as_bytes()).unwrap(); + child.wait().unwrap(); + Ok(()) + } + Err(error) => Err(error), + }.unwrap(); + let contents = fs::read_to_string(home + "/credential.toml").expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); + let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); + assert!(token.to_string().contains("test_token")); +} + +#[test] +fn save_credential_fails() { + #[cfg(debug_assertions)] + const CLI_EXE: &str = "../../../target/debug/move"; + #[cfg(not(debug_assertions))] + const CLI_EXE: &str = "../../../target/release/move"; + let home = home_dir().unwrap().to_string_lossy().to_string() + "/.move/test"; + let credential_file = home.clone() + "/credential.toml"; + let _ = fs::remove_file(&credential_file); + + fs::create_dir_all(&home).unwrap(); + let file = File::create(&credential_file).unwrap(); + let mut perms = file.metadata().unwrap().permissions(); + perms.set_mode(0o000); + file.set_permissions(perms).unwrap(); + + env::set_var("MOVE_HOME", &home); + match std::process::Command::new(CLI_EXE) + .current_dir(".") + .args(["login"]) + .stdin(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() { + Ok(mut child) => { + let token = "test_token"; + child.stdin.as_ref().unwrap().write(token.as_bytes()).unwrap(); + child.wait().unwrap(); + let out = BufReader::new(child.stderr.take().unwrap()); + out.lines().for_each(|line| + assert!(line.unwrap().contains("Error: Error reading input: Permission denied (os error 13)")) + ); + Ok(()) + } + Err(error) => Err(error), + }.unwrap(); + + let mut perms = file.metadata().unwrap().permissions(); + perms.set_mode(0o600); + file.set_permissions(perms).unwrap(); + let _ = fs::remove_file(&credential_file); +} From 8e43cc49f51f7d1dc7b74f6c92c7ddeb1d42edbb Mon Sep 17 00:00:00 2001 From: ea-open-source Date: Mon, 30 May 2022 12:18:09 +0700 Subject: [PATCH 3/3] Refactor test code --- language/tools/move-cli/src/login/cli.rs | 155 ++++++++++++------ language/tools/move-cli/src/package/cli.rs | 9 +- language/tools/move-cli/tests/cli_tests.rs | 110 +++++++++---- .../src/source_package/manifest_parser.rs | 1 - 4 files changed, 192 insertions(+), 83 deletions(-) diff --git a/language/tools/move-cli/src/login/cli.rs b/language/tools/move-cli/src/login/cli.rs index c49227fc33..361ccbbcff 100644 --- a/language/tools/move-cli/src/login/cli.rs +++ b/language/tools/move-cli/src/login/cli.rs @@ -1,9 +1,9 @@ -use std::{fs, io}; +use anyhow::{bail, Result}; use std::fs::File; use std::path::PathBuf; -use anyhow::{bail, Result}; -use toml_edit::easy::Value; +use std::{fs, io}; use toml_edit::easy::map::Map; +use toml_edit::easy::Value; pub fn handle_login_commands(config: move_package::BuildConfig) -> Result<()> { let url: &str; @@ -12,23 +12,33 @@ pub fn handle_login_commands(config: move_package::BuildConfig) -> Result<()> { } else { url = "https://movey.net"; } - println!("please paste the API Token found on {}/settings/tokens below", url); + println!( + "Please paste the API Token found on {}/settings/tokens below", + url + ); let mut line = String::new(); - match io::stdin().read_line(&mut line) { - Ok(_) => { - if let Some('\n') = line.chars().next_back() { - line.pop(); + loop { + match io::stdin().read_line(&mut line) { + Ok(_) => { + if let Some('\n') = line.chars().next_back() { + line.pop(); + } + if let Some('\r') = line.chars().next_back() { + line.pop(); + } + if line.len() != 0 { + break; + } + println!("Invalid API Token. Try again!"); } - if let Some('\r') = line.chars().next_back() { - line.pop(); + Err(err) => { + bail!("Error reading file: {}", err); } - print!("{}", line); - } - Err(err) => { - bail!("Error reading file: {}", err); } } - save_credential(line, config.test_mode) + save_credential(line, config.test_mode)?; + println!("Token for Movey saved."); + Ok(()) } pub fn save_credential(token: String, is_test_mode: bool) -> Result<()> { @@ -52,23 +62,28 @@ pub fn save_credential(token: String, is_test_mode: bool) -> Result<()> { match fs::read_to_string(&credential_path) { Ok(contents) => { old_contents = contents; - }, + } Err(error) => bail!("Error reading input: {}", error), } - let mut toml: Value = old_contents.parse() + let mut toml: Value = old_contents + .parse() .map_err(|e| anyhow::Error::from(e).context("could not parse input as TOML"))?; if let Some(registry) = toml.as_table_mut().unwrap().get_mut("registry") { if let Some(toml_token) = registry.as_table_mut().unwrap().get_mut("token") { *toml_token = Value::String(token); } else { - registry.as_table_mut().unwrap() + registry + .as_table_mut() + .unwrap() .insert(String::from("token"), Value::String(token)); } } else { let mut value = Map::new(); value.insert(String::from("token"), Value::String(token)); - toml.as_table_mut().unwrap().insert(String::from("registry"), Value::Table(value)); + toml.as_table_mut() + .unwrap() + .insert(String::from("registry"), Value::Table(value)); } let new_contents = toml.to_string(); @@ -96,85 +111,127 @@ fn set_permissions(file: &File, mode: u32) -> Result<()> { #[cfg(test)] mod tests { - use std::env; - use home::home_dir; use super::*; + use home::home_dir; + use std::env; - fn setup_home_path() -> String { - let move_home = env::var("MOVE_HOME").unwrap_or_else(|_| { + fn setup_move_home() -> (String, String) { + let mut move_home = env::var("MOVE_HOME").unwrap_or_else(|_| { env::var("HOME").unwrap_or_else(|_| { let home_dir = home_dir().unwrap().to_string_lossy().to_string(); env::set_var("HOME", &home_dir); home_dir }) }); - let credential_file = move_home + "/.move/test/credential.toml"; - return credential_file; + move_home.push_str("/.move/test"); + let credential_path = move_home.clone() + "/credential.toml"; + return (move_home, credential_path); + } + + fn clean_up() { + let (move_home, _) = setup_move_home(); + let _ = fs::remove_dir_all(move_home); } #[test] fn save_credential_works_if_no_credential_file_exists() { - let credential_file = setup_home_path(); - let _ = fs::remove_file(&credential_file); + let (move_home, credential_path) = setup_move_home(); + let _ = fs::remove_dir_all(&move_home); save_credential(String::from("test_token"), true).unwrap(); - let contents = fs::read_to_string(&credential_file).expect("Unable to read file"); + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); let mut toml: Value = contents.parse().unwrap(); let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); assert!(token.to_string().contains("test_token")); + + clean_up(); } #[test] - fn save_credential_works_if_credential_file_is_empty() { - let credential_file = setup_home_path(); + fn save_credential_works_if_empty_credential_file_exists() { + let (move_home, credential_path) = setup_move_home(); - let _ = fs::remove_file(&credential_file); - File::create(&credential_file).unwrap(); + let _ = fs::remove_dir_all(&move_home); + fs::create_dir_all(&move_home).unwrap(); + File::create(&credential_path).unwrap(); + + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + assert!(toml.as_table_mut().unwrap().get_mut("registry").is_none()); save_credential(String::from("test_token"), true).unwrap(); - let contents = fs::read_to_string(&credential_file).expect("Unable to read file"); + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); let mut toml: Value = contents.parse().unwrap(); let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); assert!(token.to_string().contains("test_token")); + + clean_up(); } #[test] - fn save_credential_works_with_old_token_field() { - let credential_file = setup_home_path(); - File::create(&credential_file).unwrap(); + fn save_credential_works_if_token_field_exists() { + let (move_home, credential_path) = setup_move_home(); - let old_content = String::from("[registry]\ntoken = \"old_test_token\"\n"); - fs::write(&credential_file, old_content).expect("Unable to write file"); + let _ = fs::remove_dir_all(&move_home); + fs::create_dir_all(&move_home).unwrap(); + File::create(&credential_path).unwrap(); - save_credential(String::from("test_token"), true).unwrap(); + let old_content = + String::from("[registry]\ntoken = \"old_test_token\"\nversion = \"0.0.0\"\n"); + fs::write(&credential_path, old_content).expect("Unable to write file"); - let contents = fs::read_to_string(&credential_file).expect("Unable to read file"); + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); let mut toml: Value = contents.parse().unwrap(); let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); - assert!(token.to_string().contains("test_token")); + assert!(token.to_string().contains("old_test_token")); + assert!(!token.to_string().contains("new_world")); + + save_credential(String::from("new_world"), true).unwrap(); + + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); + let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); + assert!(token.to_string().contains("new_world")); assert!(!token.to_string().contains("old_test_token")); + let version = registry.as_table_mut().unwrap().get_mut("version").unwrap(); + assert!(version.to_string().contains("0.0.0")); + + clean_up(); } #[test] - fn save_credential_works_with_old_empty_token_field() { - let credential_file = setup_home_path(); - File::create(&credential_file).unwrap(); + fn save_credential_works_if_empty_token_field_exists() { + let (move_home, credential_path) = setup_move_home(); - let old_content = String::from("[registry]\ntoken = \"\"\n"); - fs::write(&credential_file, old_content).expect("Unable to write file"); + let _ = fs::remove_dir_all(&move_home); + fs::create_dir_all(&move_home).unwrap(); + File::create(&credential_path).unwrap(); + + let old_content = String::from("[registry]\ntoken = \"\"\nversion = \"0.0.0\"\n"); + fs::write(&credential_path, old_content).expect("Unable to write file"); + + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); + let mut toml: Value = contents.parse().unwrap(); + let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); + let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); + assert!(!token.to_string().contains("test_token")); save_credential(String::from("test_token"), true).unwrap(); - let contents = fs::read_to_string(&credential_file).expect("Unable to read file"); + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); let mut toml: Value = contents.parse().unwrap(); let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); assert!(token.to_string().contains("test_token")); - assert!(!token.to_string().contains("old_test_token")); + let version = registry.as_table_mut().unwrap().get_mut("version").unwrap(); + assert!(version.to_string().contains("0.0.0")); + + clean_up(); } -} \ No newline at end of file +} diff --git a/language/tools/move-cli/src/package/cli.rs b/language/tools/move-cli/src/package/cli.rs index 7b3f8c5136..642aad67e0 100644 --- a/language/tools/move-cli/src/package/cli.rs +++ b/language/tools/move-cli/src/package/cli.rs @@ -1,7 +1,14 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use std::{collections::HashMap, fmt, fs::{create_dir_all, read_to_string}, io::Write, path::{Path, PathBuf}, process::ExitStatus}; +use std::{ + collections::HashMap, + fmt, + fs::{create_dir_all, read_to_string}, + io::Write, + path::{Path, PathBuf}, + process::ExitStatus, +}; // if windows #[cfg(target_family = "windows")] diff --git a/language/tools/move-cli/tests/cli_tests.rs b/language/tools/move-cli/tests/cli_tests.rs index 164a62d152..93141bc641 100644 --- a/language/tools/move-cli/tests/cli_tests.rs +++ b/language/tools/move-cli/tests/cli_tests.rs @@ -1,16 +1,18 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 -use std::{env, fs}; -use std::fs::File; -use std::io::{BufRead, BufReader, Write}; use move_cli::sandbox::commands::test; +#[cfg(unix)] +use std::fs::File; +use std::io::Write; +use std::{env, fs}; +use home::home_dir; +#[cfg(unix)] +use std::os::unix::fs::PermissionsExt; use std::path::PathBuf; use std::process::Stdio; -use home::home_dir; use toml_edit::easy::Value; -use std::os::unix::fs::PermissionsExt; pub const CLI_METATEST_PATH: [&str; 3] = ["tests", "metatests", "args.txt"]; @@ -72,59 +74,88 @@ fn save_credential_works() { const CLI_EXE: &str = "../../../target/debug/move"; #[cfg(not(debug_assertions))] const CLI_EXE: &str = "../../../target/release/move"; - let home = home_dir().unwrap().to_string_lossy().to_string() + "/.move/test"; - env::set_var("MOVE_HOME", &home); + let (move_home, credential_path) = setup_move_home(); + assert!(fs::read_to_string(&credential_path).is_err()); + match std::process::Command::new(CLI_EXE) .current_dir(".") .args(["login"]) - .stdin(Stdio::piped()).spawn() { - Ok(mut child) => { - let token = "test_token"; - child.stdin.as_ref().unwrap().write(token.as_bytes()).unwrap(); - child.wait().unwrap(); - Ok(()) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + { + Ok(child) => { + let token = "test_token"; + child + .stdin + .as_ref() + .unwrap() + .write(token.as_bytes()) + .unwrap(); + match child.wait_with_output() { + Ok(output) => { + assert!(String::from_utf8_lossy(&output.stdout).contains( + "Please paste the API Token found on \ + https://movey-app-staging.herokuapp.com/settings/tokens below" + )); + Ok(()) + } + Err(error) => Err(error), } - Err(error) => Err(error), - }.unwrap(); - let contents = fs::read_to_string(home + "/credential.toml").expect("Unable to read file"); + } + Err(error) => Err(error), + } + .unwrap(); + + let contents = fs::read_to_string(&credential_path).expect("Unable to read file"); let mut toml: Value = contents.parse().unwrap(); let registry = toml.as_table_mut().unwrap().get_mut("registry").unwrap(); let token = registry.as_table_mut().unwrap().get_mut("token").unwrap(); assert!(token.to_string().contains("test_token")); + + clean_up(&move_home) } +#[cfg(unix)] #[test] -fn save_credential_fails() { +fn save_credential_fails_if_undeletable_credential_file_exists() { #[cfg(debug_assertions)] const CLI_EXE: &str = "../../../target/debug/move"; #[cfg(not(debug_assertions))] const CLI_EXE: &str = "../../../target/release/move"; - let home = home_dir().unwrap().to_string_lossy().to_string() + "/.move/test"; - let credential_file = home.clone() + "/credential.toml"; - let _ = fs::remove_file(&credential_file); - - fs::create_dir_all(&home).unwrap(); - let file = File::create(&credential_file).unwrap(); + let (move_home, credential_path) = setup_move_home(); + let file = File::create(&credential_path).unwrap(); let mut perms = file.metadata().unwrap().permissions(); perms.set_mode(0o000); file.set_permissions(perms).unwrap(); - env::set_var("MOVE_HOME", &home); match std::process::Command::new(CLI_EXE) .current_dir(".") .args(["login"]) .stdin(Stdio::piped()) + .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn() { - Ok(mut child) => { + Ok(child) => { let token = "test_token"; child.stdin.as_ref().unwrap().write(token.as_bytes()).unwrap(); - child.wait().unwrap(); - let out = BufReader::new(child.stderr.take().unwrap()); - out.lines().for_each(|line| - assert!(line.unwrap().contains("Error: Error reading input: Permission denied (os error 13)")) - ); - Ok(()) + match child.wait_with_output() { + Ok(output) => { + assert!(String::from_utf8_lossy(&output.stdout) + .contains( + "Please paste the API Token found on \ + https://movey-app-staging.herokuapp.com/settings/tokens below" + ) + ); + assert!(String::from_utf8_lossy(&output.stderr) + .contains( + "Error: Error reading input: Permission denied (os error 13)" + ) + ); + Ok(()) + }, + Err(error) => Err(error), + } } Err(error) => Err(error), }.unwrap(); @@ -132,5 +163,20 @@ fn save_credential_fails() { let mut perms = file.metadata().unwrap().permissions(); perms.set_mode(0o600); file.set_permissions(perms).unwrap(); - let _ = fs::remove_file(&credential_file); + let _ = fs::remove_file(&credential_path); + + clean_up(&move_home) +} + +fn setup_move_home() -> (String, String) { + let move_home = home_dir().unwrap().to_string_lossy().to_string() + "/.move/test"; + env::set_var("MOVE_HOME", &move_home); + let _ = fs::remove_dir_all(&move_home); + fs::create_dir_all(&move_home).unwrap(); + let credential_path = move_home.clone() + "/credential.toml"; + return (move_home, credential_path); +} + +fn clean_up(move_home: &str) { + let _ = fs::remove_dir_all(move_home); } diff --git a/language/tools/move-package/src/source_package/manifest_parser.rs b/language/tools/move-package/src/source_package/manifest_parser.rs index 19acbbe473..428b7c949b 100644 --- a/language/tools/move-package/src/source_package/manifest_parser.rs +++ b/language/tools/move-package/src/source_package/manifest_parser.rs @@ -321,7 +321,6 @@ fn parse_dependency(tval: TV) -> Result { } (None, Some(git)) => { // Look to see if a MOVE_HOME has been set. Otherwise default to $HOME - // let a = std::env::var("MOVE_HOME").unwrap(); let move_home = std::env::var("MOVE_HOME").unwrap_or_else(|_| { format!( "{}/.move",