Skip to content

Commit

Permalink
[volta updates] Add volta_migrate and update bins with migration check
Browse files Browse the repository at this point in the history
  • Loading branch information
charlespierce committed Nov 20, 2019
1 parent cd82eec commit aa9673e
Show file tree
Hide file tree
Showing 21 changed files with 346 additions and 79 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

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

8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ cross-platform-docs = ["volta-core/cross-platform-docs"]
mock-network = ["mockito", "volta-core/mock-network"]
volta-dev = []
smoke-tests = []
volta-updates = ["volta-core/volta-updates"]
volta-updates = ["volta-migrate/volta-updates", "volta-core/volta-updates"]

[[bin]]
name = "shim"
Expand All @@ -22,6 +22,11 @@ name = "volta-shim"
path = "src/volta-shim.rs"
required-features = ["volta-updates"]

[[bin]]
name = "volta-migrate"
path = "src/volta-migrate.rs"
required-features = ["volta-updates"]

[dependencies]
atty = "0.2"
volta-core = { path = "crates/volta-core" }
Expand All @@ -45,6 +50,7 @@ test-support = { path = "crates/test-support" }
textwrap = "0.11.0"
which = "2.0.1"
dirs = "1.0.4"
volta-migrate = { path = "crates/volta-migrate", optional = true }

[target.'cfg(windows)'.dependencies]
winreg = "0.6.0"
Expand Down
2 changes: 1 addition & 1 deletion ci/run-tests-updates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ steps:
# the unit tests for all crates (without mocking the network)
# run single-threaded because some tests change environment variables,
# which is not thread-safe
- script: cargo test --features volta-updates --package volta-core --package volta-fail --package archive --package volta-fail-derive --package progress-read -- --test-threads=1
- script: cargo test --features volta-updates --package volta-core --package volta-fail --package archive --package volta-fail-derive --package progress-read --package volta-layout --package volta-layout-macro --package volta-migrate -- --test-threads=1
displayName: Unit Tests

# the acceptance tests, using network mocks
Expand Down
2 changes: 1 addition & 1 deletion ci/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ steps:
# the unit tests for all crates (without mocking the network)
# run single-threaded because some tests change environment variables,
# which is not thread-safe
- script: cargo test --package volta-core --package volta-fail --package archive --package volta-fail-derive --package progress-read -- --test-threads=1
- script: cargo test --package volta-core --package volta-fail --package archive --package volta-fail-derive --package progress-read --package volta-layout --package volta-layout-macro -- --test-threads=1
displayName: Unit Tests

# the acceptance tests, using network mocks
Expand Down
13 changes: 13 additions & 0 deletions crates/volta-core/src/error/details.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ pub enum ErrorDetails {

CouldNotDetermineTool,

/// Thrown when unable to start the migration executable
#[cfg(feature = "volta-updates")]
CouldNotStartMigration,

CreateDirError {
dir: PathBuf,
},
Expand Down Expand Up @@ -590,6 +594,13 @@ Please remove the file or pass `-f` or `--force` to override.",
{}",
REPORT_BUG_CTA
),
#[cfg(feature = "volta-updates")]
ErrorDetails::CouldNotStartMigration => write!(
f,
"Volta is out-of-date and could not start migration process.
Please ensure Volta was installed correctly."
),
ErrorDetails::CreateDirError { dir } => write!(
f,
"Could not create directory {}
Expand Down Expand Up @@ -1377,6 +1388,8 @@ impl VoltaFail for ErrorDetails {
ErrorDetails::CompletionsOutFileError { .. } => ExitCode::InvalidArguments,
ErrorDetails::ContainingDirError { .. } => ExitCode::FileSystemError,
ErrorDetails::CouldNotDetermineTool => ExitCode::UnknownError,
#[cfg(feature = "volta-updates")]
ErrorDetails::CouldNotStartMigration => ExitCode::EnvironmentError,
ErrorDetails::CreateDirError { .. } => ExitCode::FileSystemError,
ErrorDetails::CreatePostscriptError { .. } => ExitCode::FileSystemError,
ErrorDetails::CreateTempDirError { .. } => ExitCode::FileSystemError,
Expand Down
7 changes: 5 additions & 2 deletions crates/volta-core/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ use std::env;
use std::path::PathBuf;

use crate::error::ErrorDetails;
#[cfg(unix)]
use crate::shim;
use cfg_if::cfg_if;
use double_checked_cell::DoubleCheckedCell;
use lazy_static::lazy_static;
Expand All @@ -13,6 +11,8 @@ cfg_if! {
if #[cfg(feature = "volta-updates")] {
use volta_layout::v1::{VoltaHome, VoltaInstall};
} else {
#[cfg(unix)]
use crate::shim;
use volta_layout::v0::{VoltaHome, VoltaInstall};
}
}
Expand Down Expand Up @@ -46,6 +46,7 @@ pub fn volta_home<'a>() -> Fallible<&'a VoltaHome> {
// NOTE: This initialization will, on some code paths, call volta_home()
// We need to make sure that volta_home does not in turn call this method
// or we will run into problems with deadlocks
// TODO: Remove this comment when we enable Volta updates - No longer true
pub fn volta_install<'a>() -> Fallible<&'a VoltaInstall> {
VOLTA_INSTALL.get_or_try_init(|| {
let install_dir = match env::var_os("VOLTA_INSTALL_DIR") {
Expand Down Expand Up @@ -74,6 +75,7 @@ fn default_install_dir() -> Fallible<PathBuf> {
.with_context(|_| ErrorDetails::NoInstallDir)
}

#[cfg(not(feature = "volta-updates"))]
pub fn bootstrap_volta_dirs() -> Fallible<()> {
let home = volta_home()?;
home.create()
Expand All @@ -92,6 +94,7 @@ pub fn bootstrap_volta_dirs() -> Fallible<()> {
Ok(())
}

#[cfg(not(feature = "volta-updates"))]
pub fn ensure_volta_dirs_exist() -> Fallible<()> {
let home = volta_home()?;
if !home.root().exists() {
Expand Down
2 changes: 2 additions & 0 deletions crates/volta-core/src/run/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::process::{Command, ExitStatus, Output};

use crate::command::create_command;
use crate::error::ErrorDetails;
#[cfg(not(feature = "volta-updates"))]
use crate::layout::ensure_volta_dirs_exist;
use crate::platform::System;
use crate::session::Session;
Expand Down Expand Up @@ -41,6 +42,7 @@ enum CommandArg {
}

pub fn execute_tool(session: &mut Session) -> Fallible<ExitStatus> {
#[cfg(not(feature = "volta-updates"))]
ensure_volta_dirs_exist()?;

let mut args = args_os();
Expand Down
109 changes: 107 additions & 2 deletions crates/volta-layout/src/v1.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,115 @@
use volta_layout_macro::layout;
use std::path::PathBuf;

pub use super::v0::VoltaHome;
use super::executable;
use volta_layout_macro::layout;

layout! {
pub struct VoltaInstall {
"volta-shim[.exe]": shim_executable;
"volta[.exe]": main_executable;
"volta-migrate[.exe]": migrate_executable;
}

pub struct VoltaHome {
"cache": cache_dir {
"node": node_cache_dir {
"index.json": node_index_file;
"index.json.expires": node_index_expiry_file;
}
}
"bin": shim_dir {}
"log": log_dir {}
"tools": tools_dir {
"inventory": inventory_dir {
"node": node_inventory_dir {}
"packages": package_inventory_dir {}
"yarn": yarn_inventory_dir {}
}
"image": image_dir {
"node": node_image_root_dir {}
"yarn": yarn_image_root_dir {}
"packages": package_image_root_dir {}
}
"user": user_toolchain_dir {
"bins": user_bin_dir {}
"packages": user_package_dir {}
"platform.json": user_platform_file;
}
}
"tmp": tmp_dir {}
"hooks.json": user_hooks_file;
"layout.v1": layout_file;
}
}

impl VoltaHome {
pub fn package_distro_file(&self, name: &str, version: &str) -> PathBuf {
path_buf!(
self.package_inventory_dir.clone(),
format!("{}-{}.tgz", name, version)
)
}

pub fn package_distro_shasum(&self, name: &str, version: &str) -> PathBuf {
path_buf!(
self.package_inventory_dir.clone(),
format!("{}-{}.shasum", name, version)
)
}

pub fn node_image_dir(&self, node: &str, npm: &str) -> PathBuf {
path_buf!(self.node_image_root_dir.clone(), node, npm)
}

pub fn yarn_image_dir(&self, version: &str) -> PathBuf {
path_buf!(self.yarn_image_root_dir.clone(), version)
}

pub fn yarn_image_bin_dir(&self, version: &str) -> PathBuf {
path_buf!(self.yarn_image_dir(version), "bin")
}

pub fn package_image_dir(&self, name: &str, version: &str) -> PathBuf {
path_buf!(self.package_image_root_dir.clone(), name, version)
}

pub fn user_package_config_file(&self, package_name: &str) -> PathBuf {
path_buf!(
self.user_package_dir.clone(),
format!("{}.json", package_name)
)
}

pub fn user_tool_bin_config(&self, bin_name: &str) -> PathBuf {
path_buf!(self.user_bin_dir.clone(), format!("{}.json", bin_name))
}

pub fn node_npm_version_file(&self, version: &str) -> PathBuf {
path_buf!(
self.node_inventory_dir.clone(),
format!("node-v{}-npm", version)
)
}

pub fn shim_file(&self, toolname: &str) -> PathBuf {
path_buf!(self.shim_dir.clone(), executable(toolname))
}
}

#[cfg(windows)]
impl VoltaHome {
pub fn shim_git_bash_script_file(&self, toolname: &str) -> PathBuf {
path_buf!(self.shim_dir.clone(), toolname)
}

pub fn node_image_bin_dir(&self, node: &str, npm: &str) -> PathBuf {
self.node_image_dir(node, npm)
}
}

#[cfg(unix)]
impl VoltaHome {
pub fn node_image_bin_dir(&self, node: &str, npm: &str) -> PathBuf {
path_buf!(self.node_image_dir(node, npm), "bin")
}
}
13 changes: 13 additions & 0 deletions crates/volta-migrate/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "volta-migrate"
version = "0.1.0"
authors = ["Charles Pierce <cpierce.grad@gmail.com>"]
edition = "2018"

[features]
volta-updates = ["volta-fail", "volta-core/volta-updates", "volta-layout/volta-updates"]

[dependencies]
volta-core = { path = "../volta-core", optional = true }
volta-fail = { path = "../volta-fail", optional = true }
volta-layout = { path = "../volta-layout", optional = true }
1 change: 1 addition & 0 deletions crates/volta-migrate/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#![cfg(feature = "volta-updates")]
3 changes: 3 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use structopt::StructOpt;

use crate::command::{self, Command};
#[cfg(not(feature = "volta-updates"))]
use volta_core::layout;
use volta_core::session::Session;
use volta_fail::{ExitCode, Fallible};
Expand Down Expand Up @@ -47,7 +48,9 @@ pub(crate) struct Volta {

impl Volta {
pub(crate) fn run(self, session: &mut Session) -> Fallible<ExitCode> {
#[cfg(not(feature = "volta-updates"))]
layout::ensure_volta_dirs_exist()?;

if self.version {
// suffix indicator for dev build
if cfg!(debug_assertions) {
Expand Down
5 changes: 0 additions & 5 deletions src/command/setup.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use log::info;
use structopt::StructOpt;
use volta_core::layout::bootstrap_volta_dirs;
use volta_core::session::{ActivityKind, Session};
use volta_core::style::success_prefix;
use volta_fail::{ExitCode, Fallible};
Expand All @@ -14,10 +13,6 @@ impl Command for Setup {
fn run(self, session: &mut Session) -> Fallible<ExitCode> {
session.add_event_start(ActivityKind::Setup);

// ISSUE #566 - Once we have a working migration, we can leave the creation of the
// directory structure to the migration and not have to call it here

bootstrap_volta_dirs()?;
os::setup_environment()?;

info!(
Expand Down
45 changes: 45 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#![cfg(feature = "volta-updates")]
use std::process::{Command, ExitStatus};

use volta_core::error::ErrorDetails;
use volta_core::layout::{volta_home, volta_install};
use volta_fail::{ResultExt, VoltaError};

pub enum Error {
Volta(VoltaError),
Tool(i32),
}

pub fn ensure_layout() -> Result<(), Error> {
let home = volta_home().map_err(Error::Volta)?;

if !home.layout_file().exists() {
let install = volta_install().map_err(Error::Volta)?;
Command::new(install.migrate_executable())
.status()
.with_context(|_| ErrorDetails::CouldNotStartMigration)
.into_result()?;
}

Ok(())
}

pub trait IntoResult<T> {
fn into_result(self) -> Result<T, Error>;
}

impl IntoResult<()> for Result<ExitStatus, VoltaError> {
fn into_result(self) -> Result<(), Error> {
match self {
Ok(status) => {
if status.success() {
Ok(())
} else {
let code = status.code().unwrap_or(1);
Err(Error::Tool(code))
}
}
Err(err) => Err(Error::Volta(err)),
}
}
}
Loading

0 comments on commit aa9673e

Please sign in to comment.