Skip to content

Commit f3d39a5

Browse files
authored
Merge pull request #120 from PLUS-POSTECH/update-command
Update command
2 parents 310f8b1 + 4e78eaf commit f3d39a5

File tree

20 files changed

+257
-30
lines changed

20 files changed

+257
-30
lines changed

README.md

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,28 @@
1818
* [Stopping problems](#stopping-problems)
1919
* [Removing problem images](#removing-problem-images)
2020
* [Removing repositories](#removing-repositories)
21+
* [Updating repositories](#updating-repositories)
2122
* [Notes on repository and problem names](#notes-on-repository-and-problem-names)
2223
+ [Problem query](#problem-query)
2324
+ [Name rules](#name-rules)
2425
- [How to Add Soma Support to Your Repository](#how-to-add-soma-support-to-your-repository)
25-
* [`soma.toml` syntax](#-somatoml--syntax)
26+
* [`soma.toml` syntax](#somatoml-syntax)
2627
+ [The root section](#the-root-section)
27-
- [The `name` field](#the--name--field)
28-
- [The `work_dir` field (optional)](#the--work-dir--field--optional-)
29-
+ [The `[binary]` section](#the---binary---section)
30-
- [The `os` field](#the--os--field)
31-
- [The `cmd` field](#the--cmd--field)
28+
- [The `name` field](#the-name-field)
29+
- [The `work_dir` field (optional)](#the-work_dir-field-optional)
30+
+ [The `[binary]` section](#the-binary-section)
31+
- [The `os` field](#the-os-field)
32+
- [The `cmd` field](#the-cmd-field)
3233
- [File entries](#file-entries)
33-
* [The `path` field](#the--path--field)
34-
* [The `target_path` field (optional)](#the--target-path--field--optional-)
35-
* [The `public` field (optional)](#the--public--field--optional-)
34+
* [The `path` field](#the-path-field)
35+
* [The `target_path` field (optional)](#the-target_path-field-optional)
36+
* [The `public` field (optional)](#the-public-field-optional)
3637
+ [Other subconfigurations](#other-subconfigurations)
37-
* [`soma-list.toml` syntax](#-soma-listtoml--syntax)
38-
+ [The `problems` field](#the--problems--field)
38+
* [`soma-list.toml` syntax](#soma-listtoml-syntax)
39+
+ [The `problems` field](#the-problems-field)
3940
- [Development](#development)
4041
* [Prerequisites](#prerequisites)
41-
* [Testing, Building, and Running](#testing--building--and-running)
42+
* [Testing, Building, and Running](#testing-building-and-running)
4243
- [License](#license)
4344
* [Contribution](#contribution)
4445

@@ -140,13 +141,14 @@ We are expecting to release `0.1.0-alpha` soon to [crates.io].
140141

141142
### Command overview
142143

143-
144144
| | Add / Create | Remove |
145145
| -------- | ------------ | ------ |
146146
| Repository | [add](#adding-repositories) | [remove](#removing-repositories) |
147147
| Image | [build](#building-problem-images) | [clean](#removing-problem-images) |
148148
| Container | [run](#running-problems) | [stop](#stopping-problems) |
149149

150+
Additionally, [update](#updating-repositories)
151+
150152

151153
### Adding repositories
152154

@@ -249,6 +251,17 @@ $ soma remove soma-bata-list
249251
There should be no problem image or container associated to the repository when you use this command. Use `clean` and `stop` command to remove them if necessary. Auto pruning for your convenience will be implemented in the future (see [#115][issue #115]).
250252

251253

254+
### Updating repositories
255+
256+
You can update and sync repositories with `update` command:
257+
258+
```bash
259+
$ soma update soma-bata-list
260+
```
261+
262+
Note that problem containers that are already running are untouched by this command. You might want to stop, build, and run the problem again after updating a repository.
263+
264+
252265
### Notes on repository and problem names
253266

254267
#### Problem query

src/bin/soma/commands.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use soma::{Environment, Printer};
88
pub use self::{
99
add::AddCommand, build::BuildCommand, clean::CleanCommand, fetch::FetchCommand,
1010
list::ListCommand, remove::RemoveCommand, run::RunCommand, stop::StopCommand,
11+
update::UpdateCommand,
1112
};
1213

1314
pub mod add;
@@ -18,6 +19,7 @@ pub mod list;
1819
pub mod remove;
1920
pub mod run;
2021
pub mod stop;
22+
pub mod update;
2123

2224
type App = clap::App<'static, 'static>;
2325

src/bin/soma/commands/update.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use clap::{Arg, ArgMatches, SubCommand};
2+
use hyper::client::connect::Connect;
3+
4+
use soma::ops::update;
5+
use soma::prelude::*;
6+
use soma::{Environment, Printer};
7+
8+
use crate::commands::{default_runtime, App, SomaCommand};
9+
10+
pub struct UpdateCommand;
11+
12+
impl UpdateCommand {
13+
pub fn new() -> UpdateCommand {
14+
UpdateCommand {}
15+
}
16+
}
17+
18+
impl SomaCommand for UpdateCommand {
19+
const NAME: &'static str = "update";
20+
21+
fn app(&self) -> App {
22+
// TODO: update all repository when repository is omitted
23+
SubCommand::with_name(Self::NAME)
24+
.about("Updates a repository")
25+
.arg(
26+
Arg::with_name("repository")
27+
.required(true)
28+
.help("the name of the repository to update"),
29+
)
30+
}
31+
32+
fn handle_match(
33+
&self,
34+
env: Environment<impl Connect, impl Printer>,
35+
matches: &ArgMatches,
36+
) -> SomaResult<()> {
37+
update(
38+
&env,
39+
matches.value_of("repository").unwrap(),
40+
&mut default_runtime(),
41+
)
42+
}
43+
}

src/bin/soma/main.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ fn main_result() -> SomaResult<()> {
3333
let remove_command = RemoveCommand::new();
3434
let run_command = RunCommand::new();
3535
let stop_command = StopCommand::new();
36+
let update_command = UpdateCommand::new();
3637

3738
let matches = App::new("soma")
3839
.version(VERSION)
@@ -46,6 +47,7 @@ fn main_result() -> SomaResult<()> {
4647
.subcommand(remove_command.app())
4748
.subcommand(run_command.app())
4849
.subcommand(stop_command.app())
50+
.subcommand(update_command.app())
4951
.get_matches();
5052

5153
let mut data_dir = DataDirectory::new()?;
@@ -60,6 +62,7 @@ fn main_result() -> SomaResult<()> {
6062
(RemoveCommand::NAME, Some(matches)) => remove_command.handle_match(env, matches),
6163
(RunCommand::NAME, Some(matches)) => run_command.handle_match(env, matches),
6264
(StopCommand::NAME, Some(matches)) => stop_command.handle_match(env, matches),
65+
(UpdateCommand::NAME, Some(matches)) => update_command.handle_match(env, matches),
6366
_ => unreachable!(),
6467
}
6568
}

src/docker.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,16 @@ pub fn image_from_prob_exists(images: &[SomaImage], problem: &Problem) -> bool {
138138
})
139139
}
140140

141+
pub fn image_from_repo_and_prob_exists(
142+
images: &[SomaImage],
143+
repo_name: &str,
144+
prob_name: &str,
145+
) -> bool {
146+
images
147+
.iter()
148+
.any(|image| image.repo_name() == repo_name && image.prob_name() == prob_name)
149+
}
150+
141151
#[derive(Debug)]
142152
pub struct SomaContainer {
143153
repo_name: String,

src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ pub enum Error {
4040
RepositoryInUse,
4141
#[fail(display = "The specified repository is not found")]
4242
RepositoryNotFound,
43+
#[fail(
44+
display = "The repository contains changes that cannot be handled by update command; Please remove and add the repository manually"
45+
)]
46+
UnsupportedUpdate,
4347
}
4448

4549
pub type Result<T> = std::result::Result<T, failure::Error>;

src/ops.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ pub fn add(
3131

3232
env.repo_manager_mut().add_repo(repo_name, backend)?;
3333

34-
let repository = env.repo_manager().get_repo(repo_name)?;
35-
repository.update()?;
34+
let mut repository = env.repo_manager().get_repo(repo_name)?;
35+
repository.update(&[])?;
3636

3737
env.printer()
3838
.write_line(&format!("Repository added: '{}'", repo_name));
@@ -68,12 +68,6 @@ pub fn build(
6868
runtime: &mut Runtime,
6969
) -> SomaResult<()> {
7070
let problem = env.repo_manager().search_prob(prob_query)?;
71-
let repo_name = problem.repo_name();
72-
73-
let repository = env.repo_manager().get_repo(repo_name).unwrap();
74-
repository.update()?;
75-
env.printer()
76-
.write_line(&format!("Repository updated: '{}'", repo_name));
7771

7872
runtime.block_on(docker::prune_images_from_prob(&env, &problem))?;
7973
build_image(&env, &problem, runtime)?;
@@ -269,3 +263,16 @@ pub fn stop(
269263

270264
Ok(())
271265
}
266+
267+
pub fn update(
268+
env: &Environment<impl Connect, impl Printer>,
269+
repo_name: &str,
270+
runtime: &mut Runtime,
271+
) -> SomaResult<()> {
272+
let mut repository = env.repo_manager().get_repo(repo_name)?;
273+
repository.update(&runtime.block_on(docker::list_images(env))?)?;
274+
env.printer()
275+
.write_line(&format!("Repository updated: '{}'", repo_name));
276+
277+
Ok(())
278+
}

src/repository.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::path::{Path, PathBuf};
33

44
use serde::{Deserialize, Serialize};
55

6+
use crate::docker::{self, SomaImage};
67
use crate::prelude::*;
78
use crate::problem::{read_manifest, MANIFEST_FILE_NAME};
89
use crate::repository::backend::{Backend, BackendExt};
@@ -37,7 +38,7 @@ impl ProblemList {
3738
}
3839
}
3940

40-
#[derive(Clone, Deserialize, Serialize)]
41+
#[derive(Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
4142
struct ProblemIndex {
4243
name: NameString,
4344
path: PathBuf,
@@ -81,8 +82,39 @@ impl<'a> Repository<'a> {
8182
self.manager.repo_path(&self.name)
8283
}
8384

84-
pub fn update(&self) -> SomaResult<()> {
85-
self.backend.update_at(self.path())
85+
pub fn update(&mut self, images: &[SomaImage]) -> SomaResult<()> {
86+
let current_prob_set: HashSet<_> = self
87+
.prob_list
88+
.clone()
89+
.into_iter()
90+
.map(|prob_index| prob_index.name)
91+
.collect();
92+
let new_prob_list = {
93+
let temp_dir = tempfile::tempdir()?;
94+
self.backend().update_at(temp_dir.path())?;
95+
read_prob_list(temp_dir.path())?
96+
};
97+
let new_prob_set: HashSet<_> = new_prob_list
98+
.clone()
99+
.into_iter()
100+
.map(|prob_index| prob_index.name)
101+
.collect();
102+
103+
let existing_problem_removed = current_prob_set
104+
.difference(&new_prob_set)
105+
.filter(|prob_name| {
106+
docker::image_from_repo_and_prob_exists(images, &self.name, prob_name)
107+
})
108+
.count()
109+
> 0;
110+
111+
if existing_problem_removed {
112+
Err(SomaError::UnsupportedUpdate)?;
113+
}
114+
115+
self.backend.update_at(self.path())?;
116+
self.prob_list = new_prob_list;
117+
Ok(())
86118
}
87119

88120
pub fn prob_name_iter(&'a self) -> impl Iterator<Item = &'a NameString> {

src/repository/backend.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::fmt::{self, Display};
2-
use std::fs::remove_dir_all;
32
use std::path::{Path, PathBuf};
43

54
use fs_extra::dir;
65
use git2::{BranchType, ObjectType, Repository as GitRepository, ResetType};
6+
use remove_dir_all::remove_dir_all;
77
use serde::{Deserialize, Serialize};
88
use url::Url;
99

templates/binary/Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ FROM {{ binary.os }}
22

33
RUN apt-get -qq update && apt-get -yqq upgrade && apt-get install -yqq socat
44

5+
COPY image-root/ /
6+
57
ENV PROB "{{ name }}"
68
RUN useradd -m $PROB
79

8-
COPY image-root/ /
910
COPY .soma/ /.soma
1011

1112
RUN chmod 555 /.soma/configure_permissions.sh \

0 commit comments

Comments
 (0)