Skip to content
This repository was archived by the owner on May 4, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 7 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
25 changes: 25 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions language/move-command-line-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ edition = "2021"
[dependencies]
anyhow = "1.0.52"
difference = "2.0.0"
dirs-next = "2.0.0"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit. Is this a better (newer?) version of the dirs crate (https://crates.io/crates/dirs)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We chose version 2.0.0 because it already existed in another place.
We can update both later.

walkdir = "2.3.1"
sha2 = "0.9.3"
hex = "0.4.3"
num-bigint = "0.4.0"
once_cell = "1.7.2"
serde = { version = "1.0.124", features = ["derive"] }

move-core-types = { path = "../move-core/types" }
14 changes: 14 additions & 0 deletions language/move-command-line-common/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Copyright (c) The Move Contributors
// SPDX-License-Identifier: Apache-2.0

use once_cell::sync::Lazy;

/// An environment variable which can be set to cause the move compiler to generate
/// file formats at a given version. Only version v5 and greater are supported.
const BYTECODE_VERSION_ENV_VAR: &str = "MOVE_BYTECODE_VERSION";
Expand All @@ -22,3 +24,15 @@ pub fn read_bool_env_var(v: &str) -> bool {
let val = read_env_var(v).to_lowercase();
val.parse::<bool>() == Ok(true) || val.parse::<usize>() == Ok(1)
}

pub static MOVE_HOME: Lazy<String> = Lazy::new(|| {
std::env::var("MOVE_HOME").unwrap_or_else(|_| {
format!(
"{}/.move",
dirs_next::home_dir()
.expect("user's home directory not found")
.to_str()
.unwrap()
)
})
});
1 change: 1 addition & 0 deletions language/move-command-line-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod address;
pub mod character_sets;
pub mod env;
pub mod files;
pub mod movey_constants;
pub mod parser;
pub mod testing;
pub mod types;
Expand Down
8 changes: 8 additions & 0 deletions language/move-command-line-common/src/movey_constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright (c) The Diem Core Contributors
// Copyright (c) The Move Contributors
// SPDX-License-Identifier: Apache-2.0

#[cfg(debug_assertions)]
pub const MOVEY_URL: &str = "https://movey-app-staging.herokuapp.com";
#[cfg(not(debug_assertions))]
pub const MOVEY_URL: &str = "https://www.movey.net";
2 changes: 2 additions & 0 deletions language/tools/move-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ 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" }
move-disassembler = { path = "../move-disassembler" }
Expand Down
1 change: 1 addition & 0 deletions language/tools/move-cli/src/base/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod disassemble;
pub mod docgen;
pub mod errmap;
pub mod info;
pub mod movey_login;
pub mod new;
pub mod prove;
pub mod test;
Expand Down
228 changes: 228 additions & 0 deletions language/tools/move-cli/src/base/movey_login.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
// Copyright (c) The Diem Core Contributors
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A nit. For new files, use only the "Move contributors" part of the copyright notice.

// Copyright (c) The Move Contributors
// SPDX-License-Identifier: Apache-2.0

use anyhow::{bail, Result};
use clap::Parser;
use move_command_line_common::{env::MOVE_HOME, movey_constants::MOVEY_URL};
use std::{fs, fs::File, io, path::PathBuf};
use toml_edit::easy::{map::Map, Value};

pub const MOVEY_CREDENTIAL_PATH: &str = "/movey_credential.toml";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also see comment below - I doubt this path format will work on windows.


#[derive(Parser)]
#[clap(name = "movey-login")]
pub struct MoveyLogin;

impl MoveyLogin {
pub fn execute(self) -> Result<()> {
println!(
"Please paste the API Token found on {}/settings/tokens below",
MOVEY_URL
);
let mut line = String::new();
loop {
match io::stdin().read_line(&mut line) {
Ok(_) => {
line = line.trim().to_string();
if !line.is_empty() {
break;
}
println!("Invalid API Token. Try again!");
}
Err(err) => {
bail!("Error reading file: {}", err);
}
}
}
Self::save_credential(line, MOVE_HOME.clone())?;
println!("Token for Movey saved.");
Ok(())
}

pub fn save_credential(token: String, move_home: String) -> Result<()> {
fs::create_dir_all(&move_home)?;
let credential_path = move_home + MOVEY_CREDENTIAL_PATH;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tested this on Windows? I have a feeling that this style of concatenating paths will not work there. It's used in other places too (e.g., in tests) - please check that all this works on Windows.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've tested both #226 and #227 and can confirm that they works.

let credential_file = PathBuf::from(&credential_path);
if !credential_file.exists() {
let credential_file = File::create(&credential_path)?;
set_permissions(&credential_file, 0o600)?;
}

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 toml: Value = old_contents
.parse()
.map_err(|e| anyhow::Error::from(e).context("could not parse input as TOML"))?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would probably be useful to include file path in error message so that the user can act on it. For similar reason, you may add something like "Delete file to regenerate it with default settings".


// only update token key, keep the rest of the file intact
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");
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(())
}

#[cfg(not(unix))]
#[allow(unused)]
fn set_permissions(file: &File, mode: u32) -> Result<()> {
Ok(())
}

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

fn setup_move_home(test_path: &str) -> (String, String) {
let cwd = env::current_dir().unwrap();
let mut move_home: String = String::from(cwd.to_string_lossy());
if !test_path.is_empty() {
move_home.push_str(&test_path);
} else {
move_home.push_str("/test");
}
let credential_path = move_home.clone() + MOVEY_CREDENTIAL_PATH;
(move_home, credential_path)
}

fn clean_up(move_home: &str) {
let _ = fs::remove_dir_all(move_home);
}

#[test]
fn save_credential_works_if_no_credential_file_exists() {
let (move_home, credential_path) =
setup_move_home("/save_credential_works_if_no_credential_file_exists");
let _ = fs::remove_dir_all(&move_home);
MoveyLogin::save_credential(String::from("test_token"), move_home.clone()).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);
}

#[test]
fn save_credential_works_if_empty_credential_file_exists() {
let (move_home, credential_path) =
setup_move_home("/save_credential_works_if_empty_credential_file_exists");

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());

MoveyLogin::save_credential(String::from("test_token"), move_home.clone()).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);
}

#[test]
fn save_credential_works_if_token_field_exists() {
let (move_home, credential_path) =
setup_move_home("/save_credential_works_if_token_field_exists");

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 = \"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_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("old_test_token"));
assert!(!token.to_string().contains("new_world"));

MoveyLogin::save_credential(String::from("new_world"), move_home.clone()).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(&move_home);
}

#[test]
fn save_credential_works_if_empty_token_field_exists() {
let (move_home, credential_path) =
setup_move_home("/save_credential_works_if_empty_token_field_exists");

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"));

MoveyLogin::save_credential(String::from("test_token"), move_home.clone()).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"));
let version = registry.as_table_mut().unwrap().get_mut("version").unwrap();
assert!(version.to_string().contains("0.0.0"));

clean_up(&move_home);
}
}
5 changes: 4 additions & 1 deletion language/tools/move-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use base::{
build::Build, coverage::Coverage, disassemble::Disassemble, docgen::Docgen, errmap::Errmap,
info::Info, new::New, prove::Prove, test::Test,
info::Info, movey_login::MoveyLogin, new::New, prove::Prove, test::Test,
};
use move_package::BuildConfig;

Expand Down Expand Up @@ -91,6 +91,8 @@ pub enum Command {
#[clap(subcommand)]
cmd: experimental::cli::ExperimentalCommand,
},
#[clap(name = "movey-login")]
MoveyLogin(MoveyLogin),
}

pub fn run_cli(
Expand Down Expand Up @@ -121,6 +123,7 @@ pub fn run_cli(
&storage_dir,
),
Command::Experimental { storage_dir, cmd } => cmd.handle_command(&move_args, &storage_dir),
Command::MoveyLogin(c) => c.execute(),
}
}

Expand Down
Loading