mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-04 14:29:45 +00:00
compat
This commit is contained in:
1
appmgr/.gitignore
vendored
1
appmgr/.gitignore
vendored
@@ -3,3 +3,4 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
.vscode
|
.vscode
|
||||||
secrets.db
|
secrets.db
|
||||||
|
*.s9pk
|
||||||
22
appmgr/Cargo.lock
generated
22
appmgr/Cargo.lock
generated
@@ -710,6 +710,7 @@ dependencies = [
|
|||||||
"sha2 0.9.5",
|
"sha2 0.9.5",
|
||||||
"simple-logging",
|
"simple-logging",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
|
"tar",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio 1.9.0",
|
"tokio 1.9.0",
|
||||||
"tokio-compat-02",
|
"tokio-compat-02",
|
||||||
@@ -1563,6 +1564,15 @@ version = "0.1.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
|
checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-src"
|
||||||
|
version = "111.15.0+1.1.1k"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1a5f6ae2ac04393b217ea9f700cd04fa9bf3d93fae2872069f3d15d908af70a"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.65"
|
version = "0.9.65"
|
||||||
@@ -1572,6 +1582,7 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
|
"openssl-src",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
@@ -2538,6 +2549,17 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tar"
|
||||||
|
version = "0.4.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d779dc6aeff029314570f666ec83f19df7280bb36ef338442cfa8c604021b80"
|
||||||
|
dependencies = [
|
||||||
|
"filetime",
|
||||||
|
"libc",
|
||||||
|
"xattr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.2.0"
|
version = "3.2.0"
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ lazy_static = "1.4"
|
|||||||
libc = "0.2.86"
|
libc = "0.2.86"
|
||||||
log = "0.4.11"
|
log = "0.4.11"
|
||||||
nix = "0.20.0"
|
nix = "0.20.0"
|
||||||
openssl = "0.10.30"
|
openssl = { version="0.10.30", features=["vendored"] }
|
||||||
patch-db = { version="*", path="../../patch-db/patch-db" }
|
patch-db = { version="*", path="../../patch-db/patch-db" }
|
||||||
pin-project = "1.0.6"
|
pin-project = "1.0.6"
|
||||||
prettytable-rs = "0.8.0"
|
prettytable-rs = "0.8.0"
|
||||||
@@ -83,6 +83,7 @@ serde_yaml = "0.8.14"
|
|||||||
sha2 = "0.9.3"
|
sha2 = "0.9.3"
|
||||||
simple-logging = "2.0"
|
simple-logging = "2.0"
|
||||||
sqlx = { version="0.5", features=["runtime-tokio-rustls", "sqlite", "offline"] }
|
sqlx = { version="0.5", features=["runtime-tokio-rustls", "sqlite", "offline"] }
|
||||||
|
tar = "0.4.35"
|
||||||
thiserror = "1.0.24"
|
thiserror = "1.0.24"
|
||||||
tokio = { version="1.5.0", features=["full"] }
|
tokio = { version="1.5.0", features=["full"] }
|
||||||
tokio-compat-02 = "0.2.0"
|
tokio-compat-02 = "0.2.0"
|
||||||
|
|||||||
Binary file not shown.
@@ -77,6 +77,8 @@ impl DockerAction {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
cmd.stdout(std::process::Stdio::piped());
|
||||||
|
cmd.stderr(std::process::Stdio::piped());
|
||||||
let mut handle = cmd.spawn().with_kind(crate::ErrorKind::Docker)?;
|
let mut handle = cmd.spawn().with_kind(crate::ErrorKind::Docker)?;
|
||||||
if let (Some(input), Some(stdin)) = (&input_buf, &mut handle.stdin) {
|
if let (Some(input), Some(stdin)) = (&input_buf, &mut handle.stdin) {
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
@@ -133,6 +135,8 @@ impl DockerAction {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
cmd.stdout(std::process::Stdio::piped());
|
||||||
|
cmd.stderr(std::process::Stdio::piped());
|
||||||
let mut handle = cmd.spawn().with_kind(crate::ErrorKind::Docker)?;
|
let mut handle = cmd.spawn().with_kind(crate::ErrorKind::Docker)?;
|
||||||
if let (Some(input), Some(stdin)) = (&input_buf, &mut handle.stdin) {
|
if let (Some(input), Some(stdin)) = (&input_buf, &mut handle.stdin) {
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
@@ -177,9 +181,11 @@ impl DockerAction {
|
|||||||
format!("service_{}_{}", pkg_id, version)
|
format!("service_{}_{}", pkg_id, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uncontainer_name(name: &str) -> Option<&str> {
|
pub fn uncontainer_name(name: &str) -> Option<(&str, Version)> {
|
||||||
name.strip_prefix("service_")
|
name.trim_start_matches("/")
|
||||||
.and_then(|name| name.split("_").next())
|
.strip_prefix("service_")
|
||||||
|
.and_then(|name| name.split_once("_"))
|
||||||
|
.and_then(|(id, version)| Some((id, version.parse().ok()?)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn docker_args<'a>(
|
fn docker_args<'a>(
|
||||||
@@ -196,18 +202,20 @@ impl DockerAction {
|
|||||||
+ self.args.len(), // [ARG...]
|
+ self.args.len(), // [ARG...]
|
||||||
);
|
);
|
||||||
for (volume_id, dst) in &self.mounts {
|
for (volume_id, dst) in &self.mounts {
|
||||||
let src = if let Some(path) = volumes.get_path_for(pkg_id, volume_id) {
|
let volume = if let Some(v) = volumes.get(volume_id) {
|
||||||
path
|
v
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
let src = volume.path_for(pkg_id, pkg_version, volume_id);
|
||||||
res.push(OsStr::new("--mount").into());
|
res.push(OsStr::new("--mount").into());
|
||||||
res.push(
|
res.push(
|
||||||
OsString::from(format!(
|
dbg!(OsString::from(format!(
|
||||||
"type=bind,src={},dst={}",
|
"type=bind,src={},dst={}{}",
|
||||||
src.display(),
|
src.display(),
|
||||||
dst.display()
|
dst.display(),
|
||||||
))
|
if volume.readonly() { ",readonly" } else { "" }
|
||||||
|
)))
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|||||||
use crate::util::Version;
|
use crate::util::Version;
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
|
||||||
pub const SYSTEM_ID: Id<&'static str> = Id("SYSTEM");
|
pub const SYSTEM_ID: Id<&'static str> = Id("x_system");
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
#[error("Invalid ID")]
|
#[error("Invalid ID")]
|
||||||
|
|||||||
@@ -379,8 +379,6 @@ pub async fn install_s9pk<R: AsyncRead + AsyncSeek + Unpin>(
|
|||||||
let interface_info = manifest.interfaces.install(&mut sql_tx, pkg_id, ip).await?;
|
let interface_info = manifest.interfaces.install(&mut sql_tx, pkg_id, ip).await?;
|
||||||
log::info!("Install {}@{}: Installed interfaces", pkg_id, version);
|
log::info!("Install {}@{}: Installed interfaces", pkg_id, version);
|
||||||
|
|
||||||
log::info!("Install {}@{}: Complete", pkg_id, version);
|
|
||||||
|
|
||||||
let static_files = StaticFiles::local(pkg_id, version, manifest.assets.icon_type());
|
let static_files = StaticFiles::local(pkg_id, version, manifest.assets.icon_type());
|
||||||
let current_dependencies = manifest
|
let current_dependencies = manifest
|
||||||
.dependencies
|
.dependencies
|
||||||
@@ -489,11 +487,19 @@ pub async fn install_s9pk<R: AsyncRead + AsyncSeek + Unpin>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log::info!("Install {}@{}: Syncing Tor", pkg_id, version);
|
||||||
ctx.tor_controller.sync(&mut tx, &mut sql_tx).await?;
|
ctx.tor_controller.sync(&mut tx, &mut sql_tx).await?;
|
||||||
|
log::info!("Install {}@{}: Synced Tor", pkg_id, version);
|
||||||
#[cfg(feature = "avahi")]
|
#[cfg(feature = "avahi")]
|
||||||
ctx.mdns_controller.sync(&mut tx).await?;
|
{
|
||||||
|
log::info!("Install {}@{}: Syncing MDNS", pkg_id, version);
|
||||||
|
ctx.mdns_controller.sync(&mut tx).await?;
|
||||||
|
log::info!("Install {}@{}: Synced MDNS", pkg_id, version);
|
||||||
|
}
|
||||||
|
|
||||||
tx.commit(None).await?;
|
tx.commit(None).await?;
|
||||||
|
|
||||||
|
log::info!("Install {}@{}: Complete", pkg_id, version);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ pub struct S9pkPacker<
|
|||||||
RInstructions: Read,
|
RInstructions: Read,
|
||||||
RIcon: Read,
|
RIcon: Read,
|
||||||
RDockerImages: Read,
|
RDockerImages: Read,
|
||||||
|
RAssets: Read,
|
||||||
> {
|
> {
|
||||||
writer: W,
|
writer: W,
|
||||||
manifest: &'a Manifest,
|
manifest: &'a Manifest,
|
||||||
@@ -25,6 +26,7 @@ pub struct S9pkPacker<
|
|||||||
instructions: RInstructions,
|
instructions: RInstructions,
|
||||||
icon: RIcon,
|
icon: RIcon,
|
||||||
docker_images: RDockerImages,
|
docker_images: RDockerImages,
|
||||||
|
assets: RAssets,
|
||||||
}
|
}
|
||||||
impl<
|
impl<
|
||||||
'a,
|
'a,
|
||||||
@@ -33,7 +35,8 @@ impl<
|
|||||||
RInstructions: Read,
|
RInstructions: Read,
|
||||||
RIcon: Read,
|
RIcon: Read,
|
||||||
RDockerImages: Read,
|
RDockerImages: Read,
|
||||||
> S9pkPacker<'a, W, RLicense, RInstructions, RIcon, RDockerImages>
|
RAssets: Read,
|
||||||
|
> S9pkPacker<'a, W, RLicense, RInstructions, RIcon, RDockerImages, RAssets>
|
||||||
{
|
{
|
||||||
/// BLOCKING
|
/// BLOCKING
|
||||||
pub fn pack(mut self, key: &ed25519_dalek::Keypair) -> Result<(), Error> {
|
pub fn pack(mut self, key: &ed25519_dalek::Keypair) -> Result<(), Error> {
|
||||||
@@ -93,13 +96,22 @@ impl<
|
|||||||
position = new_pos;
|
position = new_pos;
|
||||||
// docker_images
|
// docker_images
|
||||||
std::io::copy(&mut self.docker_images, &mut writer)
|
std::io::copy(&mut self.docker_images, &mut writer)
|
||||||
.with_ctx(|_| (crate::ErrorKind::Filesystem, "Copying App Image"))?;
|
.with_ctx(|_| (crate::ErrorKind::Filesystem, "Copying Docker Images"))?;
|
||||||
let new_pos = writer.stream_position()?;
|
let new_pos = writer.stream_position()?;
|
||||||
header.table_of_contents.docker_images = FileSection {
|
header.table_of_contents.docker_images = FileSection {
|
||||||
position,
|
position,
|
||||||
length: new_pos - position,
|
length: new_pos - position,
|
||||||
};
|
};
|
||||||
position = new_pos;
|
position = new_pos;
|
||||||
|
// docker_images
|
||||||
|
std::io::copy(&mut self.assets, &mut writer)
|
||||||
|
.with_ctx(|_| (crate::ErrorKind::Filesystem, "Copying Assets"))?;
|
||||||
|
let new_pos = writer.stream_position()?;
|
||||||
|
header.table_of_contents.assets = FileSection {
|
||||||
|
position,
|
||||||
|
length: new_pos - position,
|
||||||
|
};
|
||||||
|
position = new_pos;
|
||||||
|
|
||||||
// header
|
// header
|
||||||
let (hash, _) = writer.finish();
|
let (hash, _) = writer.finish();
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ pub struct TableOfContents {
|
|||||||
pub instructions: FileSection,
|
pub instructions: FileSection,
|
||||||
pub icon: FileSection,
|
pub icon: FileSection,
|
||||||
pub docker_images: FileSection,
|
pub docker_images: FileSection,
|
||||||
|
pub assets: FileSection,
|
||||||
}
|
}
|
||||||
impl TableOfContents {
|
impl TableOfContents {
|
||||||
pub fn serialize<W: Write>(&self, mut writer: W) -> std::io::Result<()> {
|
pub fn serialize<W: Write>(&self, mut writer: W) -> std::io::Result<()> {
|
||||||
@@ -81,7 +82,8 @@ impl TableOfContents {
|
|||||||
+ (1 + "license".len() + 16)
|
+ (1 + "license".len() + 16)
|
||||||
+ (1 + "instructions".len() + 16)
|
+ (1 + "instructions".len() + 16)
|
||||||
+ (1 + "icon".len() + 16)
|
+ (1 + "icon".len() + 16)
|
||||||
+ (1 + "docker_images".len() + 16)) as u32;
|
+ (1 + "docker_images".len() + 16)
|
||||||
|
+ (1 + "assets".len() + 16)) as u32;
|
||||||
writer.write_all(&u32::to_be_bytes(len))?;
|
writer.write_all(&u32::to_be_bytes(len))?;
|
||||||
self.manifest.serialize_entry("manifest", &mut writer)?;
|
self.manifest.serialize_entry("manifest", &mut writer)?;
|
||||||
self.license.serialize_entry("license", &mut writer)?;
|
self.license.serialize_entry("license", &mut writer)?;
|
||||||
@@ -90,6 +92,7 @@ impl TableOfContents {
|
|||||||
self.icon.serialize_entry("icon", &mut writer)?;
|
self.icon.serialize_entry("icon", &mut writer)?;
|
||||||
self.docker_images
|
self.docker_images
|
||||||
.serialize_entry("docker_images", &mut writer)?;
|
.serialize_entry("docker_images", &mut writer)?;
|
||||||
|
self.assets.serialize_entry("assets", &mut writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub async fn deserialize<R: AsyncRead + Unpin>(mut reader: R) -> std::io::Result<Self> {
|
pub async fn deserialize<R: AsyncRead + Unpin>(mut reader: R) -> std::io::Result<Self> {
|
||||||
@@ -126,6 +129,7 @@ impl TableOfContents {
|
|||||||
instructions: from_table(&table, "instructions")?,
|
instructions: from_table(&table, "instructions")?,
|
||||||
icon: from_table(&table, "icon")?,
|
icon: from_table(&table, "icon")?,
|
||||||
docker_images: from_table(&table, "docker_images")?,
|
docker_images: from_table(&table, "docker_images")?,
|
||||||
|
assets: from_table(&table, "assets")?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,11 +139,13 @@ pub struct Assets {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub license: Option<PathBuf>,
|
pub license: Option<PathBuf>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
pub instructions: Option<PathBuf>,
|
||||||
|
#[serde(default)]
|
||||||
pub icon: Option<PathBuf>,
|
pub icon: Option<PathBuf>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub docker_images: Option<PathBuf>,
|
pub docker_images: Option<PathBuf>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub instructions: Option<PathBuf>,
|
pub assets: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
impl Assets {
|
impl Assets {
|
||||||
pub fn license_path(&self) -> &Path {
|
pub fn license_path(&self) -> &Path {
|
||||||
@@ -152,6 +154,12 @@ impl Assets {
|
|||||||
.map(|a| a.as_path())
|
.map(|a| a.as_path())
|
||||||
.unwrap_or(Path::new("LICENSE.md"))
|
.unwrap_or(Path::new("LICENSE.md"))
|
||||||
}
|
}
|
||||||
|
pub fn instructions_path(&self) -> &Path {
|
||||||
|
self.instructions
|
||||||
|
.as_ref()
|
||||||
|
.map(|a| a.as_path())
|
||||||
|
.unwrap_or(Path::new("INSTRUCTIONS.md"))
|
||||||
|
}
|
||||||
pub fn icon_path(&self) -> &Path {
|
pub fn icon_path(&self) -> &Path {
|
||||||
self.icon
|
self.icon
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -171,11 +179,11 @@ impl Assets {
|
|||||||
.map(|a| a.as_path())
|
.map(|a| a.as_path())
|
||||||
.unwrap_or(Path::new("image.tar"))
|
.unwrap_or(Path::new("image.tar"))
|
||||||
}
|
}
|
||||||
pub fn instructions_path(&self) -> &Path {
|
pub fn assets_path(&self) -> &Path {
|
||||||
self.instructions
|
self.assets
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|a| a.as_path())
|
.map(|a| a.as_path())
|
||||||
.unwrap_or(Path::new("INSTRUCTIONS.md"))
|
.unwrap_or(Path::new("assets"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use crate::s9pk::builder::S9pkPacker;
|
|||||||
use crate::s9pk::manifest::Manifest;
|
use crate::s9pk::manifest::Manifest;
|
||||||
use crate::s9pk::reader::S9pkReader;
|
use crate::s9pk::reader::S9pkReader;
|
||||||
use crate::util::display_none;
|
use crate::util::display_none;
|
||||||
|
use crate::volume::Volume;
|
||||||
use crate::{Error, ResultExt};
|
use crate::{Error, ResultExt};
|
||||||
|
|
||||||
pub mod builder;
|
pub mod builder;
|
||||||
@@ -79,6 +80,22 @@ pub fn pack(#[context] ctx: EitherContext, #[arg] path: Option<PathBuf>) -> Resu
|
|||||||
)
|
)
|
||||||
})?,
|
})?,
|
||||||
)
|
)
|
||||||
|
.assets({
|
||||||
|
let mut assets = tar::Builder::new(Vec::new()); // TODO: Ideally stream this? best not to buffer in memory
|
||||||
|
|
||||||
|
for (asset_volume, _) in manifest
|
||||||
|
.volumes
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, v)| matches!(v, &&Volume::Assets {}))
|
||||||
|
{
|
||||||
|
assets.append_dir_all(
|
||||||
|
asset_volume,
|
||||||
|
path.join(manifest.assets.assets_path()).join(asset_volume),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::io::Cursor::new(assets.into_inner()?)
|
||||||
|
})
|
||||||
.build()
|
.build()
|
||||||
.pack(&ctx.developer_key()?)?;
|
.pack(&ctx.developer_key()?)?;
|
||||||
outfile.sync_all()?;
|
outfile.sync_all()?;
|
||||||
|
|||||||
@@ -141,4 +141,8 @@ impl<R: AsyncRead + AsyncSeek + Unpin> S9pkReader<R> {
|
|||||||
pub async fn docker_images<'a>(&'a mut self) -> Result<ReadHandle<'a, R>, Error> {
|
pub async fn docker_images<'a>(&'a mut self) -> Result<ReadHandle<'a, R>, Error> {
|
||||||
Ok(self.read_handle(self.toc.docker_images).await?)
|
Ok(self.read_handle(self.toc.docker_images).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn assets<'a>(&'a mut self) -> Result<ReadHandle<'a, R>, Error> {
|
||||||
|
Ok(self.read_handle(self.toc.assets).await?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ pub async fn synchronize_all(ctx: &RpcContext) -> Result<(), Error> {
|
|||||||
let mut fuckening = false;
|
let mut fuckening = false;
|
||||||
for summary in info {
|
for summary in info {
|
||||||
let id = if let Some(id) = summary.names.iter().flatten().find_map(|s| {
|
let id = if let Some(id) = summary.names.iter().flatten().find_map(|s| {
|
||||||
DockerAction::uncontainer_name(s.as_str()).and_then(|id| pkg_ids.take(id))
|
DockerAction::uncontainer_name(s.as_str()).and_then(|(id, _)| pkg_ids.take(id))
|
||||||
}) {
|
}) {
|
||||||
id
|
id
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -518,6 +518,15 @@ impl std::fmt::Display for Version {
|
|||||||
write!(f, "{}", self.string)
|
write!(f, "{}", self.string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl std::str::FromStr for Version {
|
||||||
|
type Err = <emver::Version as FromStr>::Err;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ok(Version {
|
||||||
|
string: s.to_owned(),
|
||||||
|
version: s.parse()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
impl From<emver::Version> for Version {
|
impl From<emver::Version> for Version {
|
||||||
fn from(v: emver::Version) -> Self {
|
fn from(v: emver::Version) -> Self {
|
||||||
Version {
|
Version {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use serde::{Deserialize, Deserializer, Serialize};
|
|||||||
use crate::id::{Id, IdUnchecked};
|
use crate::id::{Id, IdUnchecked};
|
||||||
use crate::net::interface::InterfaceId;
|
use crate::net::interface::InterfaceId;
|
||||||
use crate::s9pk::manifest::PackageId;
|
use crate::s9pk::manifest::PackageId;
|
||||||
|
use crate::util::Version;
|
||||||
|
|
||||||
pub mod disk;
|
pub mod disk;
|
||||||
|
|
||||||
@@ -65,16 +66,18 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
|
|
||||||
pub struct CustomVolumeId<S: AsRef<str> = String>(Id<S>);
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||||
pub struct Volumes(IndexMap<VolumeId, Volume>);
|
pub struct Volumes(IndexMap<VolumeId, Volume>);
|
||||||
impl Volumes {
|
impl Volumes {
|
||||||
pub fn get_path_for(&self, pkg_id: &PackageId, volume_id: &VolumeId) -> Option<PathBuf> {
|
pub fn get_path_for(
|
||||||
|
&self,
|
||||||
|
pkg_id: &PackageId,
|
||||||
|
version: &Version,
|
||||||
|
volume_id: &VolumeId,
|
||||||
|
) -> Option<PathBuf> {
|
||||||
self.0
|
self.0
|
||||||
.get(volume_id)
|
.get(volume_id)
|
||||||
.map(|volume| volume.path_for(pkg_id, volume_id))
|
.map(|volume| volume.path_for(pkg_id, version, volume_id))
|
||||||
}
|
}
|
||||||
pub fn to_readonly(&self) -> Self {
|
pub fn to_readonly(&self) -> Self {
|
||||||
Volumes(
|
Volumes(
|
||||||
@@ -121,6 +124,8 @@ pub enum Volume {
|
|||||||
readonly: bool,
|
readonly: bool,
|
||||||
},
|
},
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
Assets {},
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
Pointer {
|
Pointer {
|
||||||
package_id: PackageId,
|
package_id: PackageId,
|
||||||
volume_id: VolumeId,
|
volume_id: VolumeId,
|
||||||
@@ -134,22 +139,31 @@ pub enum Volume {
|
|||||||
Backup { readonly: bool },
|
Backup { readonly: bool },
|
||||||
}
|
}
|
||||||
impl Volume {
|
impl Volume {
|
||||||
pub fn path_for(&self, pkg_id: &PackageId, volume_id: &VolumeId) -> PathBuf {
|
pub fn path_for(&self, pkg_id: &PackageId, version: &Version, volume_id: &VolumeId) -> PathBuf {
|
||||||
match self {
|
match self {
|
||||||
Volume::Data { .. } => Path::new(PKG_VOLUME_DIR)
|
Volume::Data { .. } => Path::new(PKG_VOLUME_DIR)
|
||||||
.join(pkg_id)
|
.join(pkg_id)
|
||||||
.join("volumes")
|
.join("volumes")
|
||||||
.join(volume_id),
|
.join(volume_id),
|
||||||
|
Volume::Assets {} => Path::new(PKG_VOLUME_DIR)
|
||||||
|
.join(pkg_id)
|
||||||
|
.join("assets")
|
||||||
|
.join(version.as_str())
|
||||||
|
.join(volume_id),
|
||||||
Volume::Pointer {
|
Volume::Pointer {
|
||||||
package_id,
|
package_id,
|
||||||
volume_id,
|
volume_id,
|
||||||
path,
|
path,
|
||||||
..
|
..
|
||||||
} => Path::new(PKG_VOLUME_DIR)
|
} => dbg!(Path::new(PKG_VOLUME_DIR)
|
||||||
.join(package_id)
|
.join(package_id)
|
||||||
.join("volumes")
|
.join("volumes")
|
||||||
.join(volume_id)
|
.join(volume_id)
|
||||||
.join(path),
|
.join(if path.is_absolute() {
|
||||||
|
path.strip_prefix("/").unwrap()
|
||||||
|
} else {
|
||||||
|
path.as_ref()
|
||||||
|
})),
|
||||||
Volume::Certificate { interface_id } => Path::new(PKG_VOLUME_DIR)
|
Volume::Certificate { interface_id } => Path::new(PKG_VOLUME_DIR)
|
||||||
.join(pkg_id)
|
.join(pkg_id)
|
||||||
.join("certificates")
|
.join("certificates")
|
||||||
@@ -174,6 +188,7 @@ impl Volume {
|
|||||||
pub fn readonly(&self) -> bool {
|
pub fn readonly(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Volume::Data { readonly } => *readonly,
|
Volume::Data { readonly } => *readonly,
|
||||||
|
Volume::Assets {} => true,
|
||||||
Volume::Pointer { readonly, .. } => *readonly,
|
Volume::Pointer { readonly, .. } => *readonly,
|
||||||
Volume::Certificate { .. } => true,
|
Volume::Certificate { .. } => true,
|
||||||
Volume::Backup { readonly } => *readonly,
|
Volume::Backup { readonly } => *readonly,
|
||||||
|
|||||||
4
compat/.gitignore
vendored
Normal file
4
compat/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/target
|
||||||
|
**/*.rs.bk
|
||||||
|
.DS_Store
|
||||||
|
.vscode
|
||||||
3079
compat/Cargo.lock
generated
Normal file
3079
compat/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
13
compat/Cargo.toml
Normal file
13
compat/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "compat"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Aiden McClelland <me@drbonez.dev>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = "2.33.3"
|
||||||
|
serde = { version="1.0.118", features=["derive", "rc"] }
|
||||||
|
serde_yaml = "0.8.17"
|
||||||
|
embassy-os = { path="../appmgr", default-features=false }
|
||||||
5
compat/Dockerfile
Normal file
5
compat/Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
ADD ./target/aarch64-unknown-linux-musl/release/compat /usr/local/bin/compat
|
||||||
|
|
||||||
|
ENTRYPOINT ["compat"]
|
||||||
45
compat/src/main.rs
Normal file
45
compat/src/main.rs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
use std::{fs::File, io::stdout, path::Path};
|
||||||
|
|
||||||
|
use clap::{App, Arg, SubCommand};
|
||||||
|
use embassy::config::action::{ConfigRes, SetResult};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let app = App::new("compat").subcommand(
|
||||||
|
SubCommand::with_name("config").subcommand(
|
||||||
|
SubCommand::with_name("get")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("mountpoint")
|
||||||
|
.help("The `mount` field from manifest.yaml")
|
||||||
|
.required(true),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("spec")
|
||||||
|
.help("The path to the config spec in the container")
|
||||||
|
.required(true),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
let matches = app.get_matches();
|
||||||
|
match matches.subcommand() {
|
||||||
|
("config", Some(sub_m)) => match sub_m.subcommand() {
|
||||||
|
("get", Some(sub_m)) => {
|
||||||
|
let cfg_path =
|
||||||
|
Path::new(sub_m.value_of("mountpoint").unwrap()).join("start9/config.yaml");
|
||||||
|
let cfg = if cfg_path.exists() {
|
||||||
|
Some(serde_yaml::from_reader(File::open(cfg_path).unwrap()).unwrap())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let spec_path = Path::new(sub_m.value_of("spec").unwrap());
|
||||||
|
let spec = serde_yaml::from_reader(File::open(spec_path).unwrap()).unwrap();
|
||||||
|
serde_yaml::to_writer(stdout(), &ConfigRes { config: cfg, spec }).unwrap();
|
||||||
|
}
|
||||||
|
(subcmd, _) => {
|
||||||
|
panic!("unknown subcommand: {}", subcmd);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(subcmd, _) => {
|
||||||
|
panic!("unknown subcommand: {}", subcmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user