Skip to content

Commit 633a9c2

Browse files
committed
feat: add way to access and shim internal binaries
1 parent a81210a commit 633a9c2

File tree

6 files changed

+110
-15
lines changed

6 files changed

+110
-15
lines changed

README.md

+39
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ hbox offers the following features:
1616
- **Robust Configuration Options**: hbox enables high customization through configuration files. You can define package aliases and setup automatic volume mounts via `config.json`.
1717
- **Support for Pipes**: hbox supports the use of pipes in `hbox run`, which allows you to chain commands efficiently.
1818
- **Convenient Shims**: hbox creates `shims` (alias shortcuts) for all installed packages, simplifying command entry from `hbox run <package alias> <commands>` to `<package alias> <commands>`.
19+
- **Accessible Internal Binaries**: hbox has the ability to provide direct access to internal binaries within images. Users can override the default entrypoint, meaning essential tools and utilities within containers can be accessed directly. This feature further expands the capabilities of hbox `shims`, making it even more convenient to launch and utilize container tools.
1920

2021
## Commands
2122

@@ -68,6 +69,44 @@ In the future this will be centralized in on its own repo/server, so you can fet
6869
```json
6970
{
7071
"packages": {
72+
"busybox": {
73+
"image": "docker.io/busybox",
74+
"volumes": [
75+
{
76+
"source": ".",
77+
"target": "/app"
78+
}
79+
],
80+
"current_directory": "/app",
81+
"binaries": [
82+
{
83+
"name": "tree",
84+
"path": "/bin/tree"
85+
}
86+
],
87+
"only_shim_binaries": true
88+
},
89+
"golang": {
90+
"image": "docker.io/golang",
91+
"volumes": [
92+
{
93+
"source": ".",
94+
"target": "/app"
95+
}
96+
],
97+
"current_directory": "/app",
98+
"binaries": [
99+
{
100+
"name": "go",
101+
"path": "/usr/local/go/bin/go"
102+
},
103+
{
104+
"name": "gofmt",
105+
"path": "/usr/local/go/bin/gofmt"
106+
}
107+
],
108+
"only_shim_binaries": true
109+
},
71110
"curl": {
72111
"image": "docker.io/curlimages/curl"
73112
},

src/commands.rs

+30-9
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ pub fn remove_package(name: String, version: Option<String>) -> Result<(), Box<d
8585
if package.versions.versions.contains(&version) {
8686
package.versions.versions.retain(|v| v != version.as_str());
8787
if package.versions.versions.is_empty() {
88-
do_remove_package(&name)?;
88+
do_remove_package(package)?;
8989
println!("Removed package '{}'.", name);
9090
} else {
9191
upsert(&name, package)?;
@@ -97,8 +97,8 @@ pub fn remove_package(name: String, version: Option<String>) -> Result<(), Box<d
9797
}
9898
}
9999
}
100-
(Some(_), None) => {
101-
do_remove_package(&name)?;
100+
(Some(package), None) => {
101+
do_remove_package(package)?;
102102
println!("Removed package '{}'.", name);
103103
Ok(())
104104
}
@@ -126,8 +126,15 @@ pub fn set_package_version(name: String, version: String) -> Result<(), Box<dyn
126126
}
127127

128128
pub fn run_package(name: String, subcommand: Vec<String>) -> Result<(), Box<dyn Error>> {
129-
if let Some(package) = Package::load(&name)? {
130-
run(&package, &subcommand);
129+
let parts: Vec<&str> = name.split("::").collect();
130+
let (package_name, binary) = match parts.as_slice() {
131+
[package_name] => (package_name.to_string(), None),
132+
[package_name, binary] => (package_name.to_string(), Some(binary.to_string())),
133+
_ => return Err(format!("Invalid package name '{}'.", name).into()),
134+
};
135+
136+
if let Some(package) = Package::load(&package_name)? {
137+
run(&package, binary, &subcommand);
131138
Ok(())
132139
} else {
133140
Err(format!("Package '{}' does not exists.", name).into())
@@ -138,16 +145,30 @@ fn do_add_package(name: &String, version: &String, package: Package) -> Result<(
138145
let mut new_package = package.clone();
139146
new_package.versions.current = version.clone();
140147
if crate::runner::pull(&new_package) {
148+
if !&package.index.only_shim_binaries {
149+
add_shim(&name, None)?;
150+
}
151+
if let Some(binaries) = &package.index.binaries {
152+
for binary in binaries {
153+
add_shim(&name, Some(&binary.name))?;
154+
}
155+
}
141156
upsert(&name, package)?;
142-
add_shim(&name)?;
143157
Ok(())
144158
} else {
145159
Err(format!("Failed to add package '{}' at version '{}'.", name, version).into())
146160
}
147161
}
148162

149-
fn do_remove_package(name: &String) -> Result<(), Box<dyn Error>> {
150-
remove(&name)?;
151-
remove_shim(&name)?;
163+
fn do_remove_package(package: Package) -> Result<(), Box<dyn Error>> {
164+
remove(&package.name)?;
165+
if !&package.index.only_shim_binaries {
166+
remove_shim(&package.name)?;
167+
}
168+
if let Some(binaries) = &package.index.binaries {
169+
for binary in binaries {
170+
remove_shim(&binary.name)?;
171+
}
172+
}
152173
Ok(())
153174
}

src/files/index.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,19 @@ pub struct Package {
1414
pub image: String,
1515
pub volumes: Option<Vec<Volume>>,
1616
pub current_directory: Option<String>,
17+
pub binaries: Option<Vec<Binary>>,
18+
#[serde(default)]
19+
pub only_shim_binaries: bool,
1720
}
1821

1922
impl Package {
2023
pub fn new(name: &str) -> Self {
2124
Package {
2225
image: format!("docker.io/{}", name),
2326
volumes: None,
24-
current_directory: None
27+
current_directory: None,
28+
binaries: None,
29+
only_shim_binaries: false
2530
}
2631
}
2732
}
@@ -32,6 +37,12 @@ pub struct Volume {
3237
pub target: String,
3338
}
3439

40+
#[derive(Serialize, Deserialize, Debug, Clone)]
41+
pub struct Binary {
42+
pub name: String,
43+
pub path: String,
44+
}
45+
3546
pub fn parse() -> Result<Root, Box<dyn Error>> {
3647
let config = AppConfig::new();
3748
parse_json(&config.index_path())

src/packages.rs

+7
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ impl Package {
5757
println!(" - {}:{}", volume.source, volume.target);
5858
}
5959
}
60+
if let Some(binaries) = &self.index.binaries {
61+
println!(" - binaries:");
62+
for binary in binaries {
63+
println!(" - {} -> {}", binary.name, binary.path);
64+
}
65+
}
66+
println!(" - only_shim_binaries: {}", &self.index.only_shim_binaries);
6067
if let Some(current_directory) = &self.index.current_directory {
6168
println!(" - current directory: {}", current_directory.clone());
6269
}

src/runner.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ fn run_command(command: &str, stdin_buffer: Option<Vec<u8>>) -> bool {
3737
}
3838
}
3939

40-
pub fn run(package: &Package, params: &Vec<String>) -> bool {
40+
pub fn run(package: &Package, binary: Option<String>, params: &Vec<String>) -> bool {
4141
let interactive = !atty::is(Stream::Stdin);
4242

4343
let mut buffer = Vec::new();
@@ -69,6 +69,17 @@ pub fn run(package: &Package, params: &Vec<String>) -> bool {
6969
args.push(current_directory.clone());
7070
}
7171

72+
if let Some(b) = binary {
73+
if let Some(binaries) = &package.index.binaries {
74+
for binary in binaries {
75+
if binary.name == b {
76+
args.push("--entrypoint".to_string());
77+
args.push(binary.path.to_string());
78+
}
79+
}
80+
}
81+
}
82+
7283
args.push(format!(
7384
"{}:{}",
7485
package.index.image.clone(),

src/shims.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,26 @@ use std::fs::{self, File};
33
use std::io::Write;
44
use std::path::PathBuf;
55

6-
pub fn add_shim(name: &str) -> std::io::Result<()> {
6+
pub fn add_shim(name: &str, binary: Option<&str>) -> std::io::Result<()> {
77
let config = AppConfig::new();
8-
let shims_file_path = get_shims_path(name, config);
8+
let shim_name = binary.unwrap_or_else(|| name);
9+
let shims_file_path = get_shims_path(shim_name, config);
910

1011
if !shims_file_path.exists() {
1112
fs::create_dir_all(shims_file_path.parent().unwrap())?;
1213
let mut shim_file = File::create(&shims_file_path)?;
1314

15+
let command = match binary {
16+
Some(bin) => format!("{}::{}", name, bin),
17+
None => name.to_string()
18+
};
19+
1420
if std::env::consts::OS == "windows" {
1521
shim_file.write_all(b"@echo off\n")?;
16-
shim_file.write_all(format!("hbox.exe run {} %*\n", name).as_bytes())?;
22+
shim_file.write_all(format!("hbox.exe run {} %*\n", command).as_bytes())?;
1723
} else {
1824
shim_file.write_all(b"#!/bin/sh\n")?;
19-
shim_file.write_all(format!("hbox run {} \"$@\"\n", name).as_bytes())?;
25+
shim_file.write_all(format!("hbox run {} \"$@\"\n", command).as_bytes())?;
2026
}
2127

2228
if std::env::consts::OS != "windows" {

0 commit comments

Comments
 (0)