Skip to content
This repository has been archived by the owner on Aug 3, 2023. It is now read-only.

Commit

Permalink
don't install binary dependencies on every action
Browse files Browse the repository at this point in the history
  • Loading branch information
EverlastingBugstopper committed Jan 21, 2020
1 parent 0062c69 commit f578b30
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 89 deletions.
7 changes: 4 additions & 3 deletions Cargo.lock

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

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ build = "build.rs"

[dependencies]
atty = "0.2.11"
binary-install = "0.0.3-alpha"
binary-install = {git = "https://github.com/everlastingbugstopper/binary-install-rs", rev = "de69baf"}
clap = "2.32.0"
config = "0.9.2"
console = "0.7.5"
Expand Down Expand Up @@ -48,10 +48,14 @@ data-encoding = "2.1.2"
ignore = "0.4.10"
tempfile = "3.1.0"
indicatif = "0.13.0"
semver = "0.9.0"

[dev-dependencies]
assert_cmd = "0.11.1"
fs_extra = "1.1.0"

[features]
vendored-openssl = ['openssl/vendored']

[profile.release]
debug = true
6 changes: 5 additions & 1 deletion src/commands/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ pub fn build(target: &Target) -> Result<(), failure::Error> {
}
TargetType::Rust => {
let tool_name = "wasm-pack";
let binary_path = install::install(tool_name, "rustwasm")?.binary(tool_name)?;
let tool_author = "rustwasm";
let is_binary = true;
let version = install::get_latest_version(tool_name)?;
let binary_path =
install::install(tool_name, tool_author, is_binary, version)?.binary(tool_name)?;
let args = ["build", "--target", "no-modules"];

let command = command(&args, &binary_path);
Expand Down
6 changes: 5 additions & 1 deletion src/commands/build/watch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ pub fn watch_and_build(
}
TargetType::Rust => {
let tool_name = "wasm-pack";
let binary_path = install::install(tool_name, "rustwasm")?.binary(tool_name)?;
let tool_author = "rustwasm";
let is_binary = true;
let version = install::get_latest_version(tool_name)?;
let binary_path =
install::install(tool_name, tool_author, is_binary, version)?.binary(tool_name)?;
let args = ["build", "--target", "no-modules"];

thread::spawn(move || {
Expand Down
13 changes: 10 additions & 3 deletions src/commands/build/wranglerjs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use notify::{self, RecursiveMode, Watcher};
use output::WranglerjsOutput;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use semver::Version;

use crate::commands::build::watch::wait_for_changes;
use crate::commands::build::watch::COOLDOWN_PERIOD;
Expand Down Expand Up @@ -167,7 +168,11 @@ fn setup_build(target: &Target) -> Result<(Command, PathBuf, Bundle), failure::E

// export WASM_PACK_PATH for use by wasm-pack-plugin
// https://github.com/wasm-tool/wasm-pack-plugin/blob/caca20df84782223f002735a8a2e99b2291f957c/plugin.js#L13
let wasm_pack_path = install::install("wasm-pack", "rustwasm")?.binary("wasm-pack")?;
let tool_name = "wasm-pack";
let tool_author = "rustwasm";
let version = install::get_latest_version(tool_name)?;
let wasm_pack_path =
install::install(tool_name, tool_author, true, version)?.binary("wasm-pack")?;
command.env("WASM_PACK_PATH", wasm_pack_path);

// create a temp file for IPC with the wranglerjs process
Expand Down Expand Up @@ -302,8 +307,10 @@ fn install() -> Result<PathBuf, failure::Error> {
wranglerjs_path
} else {
let tool_name = "wranglerjs";
let version = env!("CARGO_PKG_VERSION");
let wranglerjs_path = install::install_artifact(tool_name, "cloudflare", version)?;
let tool_author = "cloudflare";
let is_binary = false;
let version = Version::parse(env!("CARGO_PKG_VERSION"))?;
let wranglerjs_path = install::install(tool_name, tool_author, is_binary, version)?;
log::info!("wranglerjs downloaded at: {:?}", wranglerjs_path.path());
wranglerjs_path.path()
};
Expand Down
6 changes: 5 additions & 1 deletion src/commands/generate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ pub fn generate(

pub fn run_generate(name: &str, template: &str) -> Result<(), failure::Error> {
let tool_name = "cargo-generate";
let binary_path = install::install(tool_name, "ashleygwilliams")?.binary(tool_name)?;
let tool_author = "ashleygwilliams";
let is_binary = true;
let version = install::get_latest_version(tool_name)?;
let binary_path =
install::install(tool_name, tool_author, is_binary, version)?.binary(tool_name)?;

let args = ["generate", "--git", template, "--name", name, "--force"];

Expand Down
136 changes: 57 additions & 79 deletions src/install/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,99 +6,78 @@ use crate::terminal::emoji;
use binary_install::{Cache, Download};
use krate::Krate;
use log::info;
use which::which;
use semver::Version;

use std::env;
use std::path::Path;
use std::process::Command;
use std::fs;
use std::path::{Path, PathBuf};

use lazy_static::lazy_static;

lazy_static! {
static ref CACHE: Cache = get_wrangler_cache().expect("creating binary dependency cache");
static ref CACHE: Cache = get_wrangler_cache().expect("Could not get Wrangler cache location");
}

pub fn install(tool_name: &str, owner: &str) -> Result<Download, failure::Error> {
if let Some(download) = tool_exists(tool_name)? {
return Ok(download);
}

let binaries = &[tool_name];
let latest_version = get_latest_version(tool_name)?;
let download = download_prebuilt(tool_name, owner, &latest_version, binaries);
match download {
Ok(download) => Ok(download),
Err(e) => {
failure::bail!("could not download pre-built `{}` ({}).", tool_name, e);
}
}
enum ToolDownload {
NeedsInstall(Version),
InstalledAt(Download),
}

pub fn install_artifact(
pub fn install(
tool_name: &str,
owner: &str,
version: &str,
is_binary: bool,
version: Version,
) -> Result<Download, failure::Error> {
if let Some(download) = tool_exists(tool_name)? {
return Ok(download);
}

let download = download_prebuilt(tool_name, owner, version, &[]);
match download {
Ok(download) => Ok(download),
Err(e) => {
failure::bail!("could not download pre-built `{}` ({}).", tool_name, e);
match tool_needs_update(tool_name, version)? {
ToolDownload::NeedsInstall(version) => {
println!("{} Installing {} v{}...", emoji::DOWN, tool_name, version);
let binaries: Vec<&str> = if is_binary { vec![tool_name] } else { vec![] };
let download =
download_prebuilt(tool_name, owner, &version.to_string(), binaries.as_ref());
match download {
Ok(download) => Ok(download),
Err(e) => failure::bail!("could not download `{}`\n{}", tool_name, e),
}
}
ToolDownload::InstalledAt(download) => Ok(download),
}
}

fn tool_exists(tool_name: &str) -> Result<Option<Download>, failure::Error> {
if let Ok(path) = which(tool_name) {
let no_parent_msg = format!("{} There is no path parent", emoji::WARN);
log::debug!("found global {} binary at: {}", tool_name, path.display());
if !tool_needs_update(tool_name, &path)? {
return Ok(Some(Download::at(path.parent().expect(&no_parent_msg))));
fn tool_needs_update(
tool_name: &str,
target_version: Version,
) -> Result<ToolDownload, failure::Error> {
if let Some((installed_version, installed_location)) =
get_installation(tool_name, &target_version)?
{
if installed_version == target_version {
return Ok(ToolDownload::InstalledAt(Download::at(&installed_location)));
}
}

Ok(None)
Ok(ToolDownload::NeedsInstall(target_version))
}

fn tool_needs_update(tool_name: &str, path: &Path) -> Result<bool, failure::Error> {
let no_version_msg = format!("failed to find version for {}", tool_name);

let tool_version_output = Command::new(path.as_os_str())
.arg("--version")
.output()
.expect(&no_version_msg);

if !tool_version_output.status.success() {
let error = String::from_utf8_lossy(&tool_version_output.stderr);
log::debug!("could not find version for {}\n{}", tool_name, error);
return Ok(true);
}

let installed_tool_version = String::from_utf8_lossy(&tool_version_output.stdout);
let installed_tool_version = match installed_tool_version.split_whitespace().last() {
None => return Ok(true),
Some(v) => v,
};
let latest_tool_version = get_latest_version(tool_name)?;
if installed_tool_version == latest_tool_version {
log::debug!(
"installed {} version {} is up to date",
tool_name,
installed_tool_version
);
return Ok(false);
fn get_installation(
tool_name: &str,
target_version: &Version,
) -> Result<Option<(Version, PathBuf)>, failure::Error> {
for entry in fs::read_dir(&CACHE.destination)? {
let entry = entry?;
let filename = entry.file_name().into_string();
if let Ok(filename) = filename {
if filename.starts_with(tool_name) {
let installed_version = filename
.split(&format!("{}-", tool_name))
.collect::<Vec<&str>>()[1];
let installed_version = Version::parse(installed_version)?;
if &installed_version == target_version {
return Ok(Some((installed_version, entry.path())));
}
}
}
}
log::info!(
"installed {} version {} is out of date with latest version {}",
tool_name,
installed_tool_version,
latest_tool_version
);
Ok(true)
Ok(None)
}

fn download_prebuilt(
Expand All @@ -119,16 +98,13 @@ fn download_prebuilt(

// no binaries are expected; downloading it as an artifact
let res = if !binaries.is_empty() {
CACHE.download(true, tool_name, binaries, &url)?
CACHE.download_version(true, tool_name, binaries, &url, version)?
} else {
CACHE.download_artifact(tool_name, &url)?
CACHE.download_artifact_version(tool_name, &url, version)?
};

match res {
Some(download) => {
println!("⬇️ Installing {}...", tool_name);
Ok(download)
}
Some(download) => Ok(download),
None => failure::bail!("{} is not installed!", tool_name),
}
}
Expand Down Expand Up @@ -158,8 +134,10 @@ fn prebuilt_url(tool_name: &str, owner: &str, version: &str) -> Option<String> {
}
}

fn get_latest_version(tool_name: &str) -> Result<String, failure::Error> {
Ok(Krate::new(tool_name)?.max_version)
pub fn get_latest_version(tool_name: &str) -> Result<Version, failure::Error> {
let latest_version = Krate::new(tool_name)?.max_version;
Version::parse(&latest_version)
.map_err(|e| failure::format_err!("could not parse latest version\n{}", e))
}

fn get_wrangler_cache() -> Result<Cache, failure::Error> {
Expand Down
1 change: 1 addition & 0 deletions src/terminal/emoji.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use console::Emoji;
pub static BICEP: Emoji = Emoji("💪 ", "");
pub static CRAB: Emoji = Emoji("🦀 ", "");
pub static DANCERS: Emoji = Emoji("👯 ", "");
pub static DOWN: Emoji = Emoji("⬇️ ", "");
pub static EYES: Emoji = Emoji("👀 ", "");
pub static FILES: Emoji = Emoji("🗂️ ", "");
pub static INBOX: Emoji = Emoji("📥 ", "");
Expand Down

0 comments on commit f578b30

Please sign in to comment.