oci_util/container/
mod.rs1use crate::distribution::pull::pull;
2use crate::filesystem::FileSystem;
3use crate::image::config::ConfigFile;
4use crate::image::layer::tar_file::TarFileTy;
5use crate::image::manifest::Manifest;
6use crate::image::Repositories;
7use crate::util::DigestPre;
8use anyhow::{anyhow, Error, Result};
9use log::{debug, info, warn};
10use oci_distribution::secrets::RegistryAuth;
11use oci_distribution::Reference;
12use std::fs::File;
13use std::path::PathBuf;
14
15pub async fn init(image: &Reference, auth: &RegistryAuth, force: bool) -> Result<Container> {
19 let repo = Repositories::init()?;
24 let manifest_digest = match repo.image_digest(&image) {
25 Some(digest) => digest.get_digest()?,
26 None => {
27 info!("本地未找到镜像{:?},先拉取镜像!", image);
28 pull(image, auth).await?
29 }
30 };
31 let path = FileSystem.container()?.join(&manifest_digest);
32
33 let manifest = Manifest::load(manifest_digest.as_str())?.to_oci_manifest()?;
34
35 let config = ConfigFile::load(&manifest.config.digest.get_digest()?)?;
36
37 let container = Container { path, config };
38 if force {
39 container.clear()?;
40 } else {
41 if container.exists() {
42 debug!("local disk had a container");
43 return Ok(container);
44 }
45 }
46 container.init()?;
47 Ok(container)
48}
49
50pub struct Container {
51 pub config: ConfigFile,
52 pub path: PathBuf,
53}
54
55impl Container {
56 pub fn cmd(&self) -> PathBuf {
57 let path = self.path.join(self.config.cmd.as_str());
58 debug!("base={:?} path={:?}", self.path, path);
59 path
60 }
61 pub fn exists(&self) -> bool {
62 self.path.exists()
63 }
64 pub fn clear(&self) -> Result<()> {
65 if self.exists() {
66 std::fs::remove_dir_all(&self.path)?;
67 }
68 Ok(())
69 }
70 pub fn init(&self) -> Result<()> {
71 let config = &self.config;
72 std::fs::create_dir_all(&self.path)?;
73 for copy in config.rootf.diff_ids.as_slice() {
74 debug!("read layer {:?}", copy);
75 let file = std::fs::File::open(FileSystem.layer_blobs()?.join(copy.get_digest()?))?;
76 let mut archive = tar::Archive::new(file);
77 let entries = archive.entries().unwrap();
78 for (_index, item) in entries.enumerate() {
79 if let Ok(item) = item {
80 if let Some(path) = item.path()?.to_str().and_then(|x| Some(x.to_string())) {
81 let tar_file: TarFileTy = path.into();
82 apply_tar_file(tar_file, &self.path, item)?;
83 } else {
84 warn!("archive.entries.item has not path")
85 }
86 } else {
87 warn!("archive.entries.item fail")
88 }
89 }
90 }
91 Ok(())
92 }
93}
94
95pub fn apply_tar_file(
96 tar_file_ty: TarFileTy,
97 base: &PathBuf,
98 mut item: tar::Entry<File>,
99) -> Result<()> {
100 debug!("{:?}", tar_file_ty);
101 match tar_file_ty {
102 TarFileTy::Delete(file) => {
103 let target_path = base.join(&file);
104 debug!("target: {:?}", target_path);
105 if item.header().entry_type().is_file() {
106 std::fs::remove_file(&target_path)?;
107 } else if item.header().entry_type().is_dir() {
108 std::fs::remove_dir_all(&target_path)?;
109 } else {
110 warn!("暂不支持其他文件类型: {:?}", item.header().entry_type());
111 }
112 }
113 TarFileTy::Update(file) => {
114 let target_path = base.join(&file);
115 debug!("target: {:?}", target_path,);
116 if item.header().entry_type().is_file() {
117 let mut file = std::fs::File::create(target_path)?;
118 std::io::copy(&mut item, &mut file)?;
121 } else if item.header().entry_type().is_dir() {
122 std::fs::create_dir_all(target_path)?;
123 } else {
124 warn!("暂不支持其他文件类型: {:?}", item.header().entry_type());
125 }
126 }
127 }
128 Ok(())
129}
130
131impl TryFrom<&Reference> for Container {
132 type Error = Error;
133
134 fn try_from(image: &Reference) -> std::result::Result<Self, Self::Error> {
135 let repo = Repositories::init()?;
136 let config_digest = repo
137 .image_digest(&image)
138 .ok_or(anyhow!("本地未找到镜像{:?}", image))?;
139 let path = FileSystem.container()?.join(&config_digest);
140 let config = ConfigFile::load(&config_digest)?;
141 Ok(Self { path, config })
142 }
143}