-
Notifications
You must be signed in to change notification settings - Fork 39
/
lib.rs
170 lines (146 loc) · 5.47 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// Copyright 2022 VMware, Inc.
// SPDX-License-Identifier: Apache-2.0
use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use std::{
fs,
path::{Path, PathBuf},
};
use wws_project::{check_runtime, metadata::Runtime};
/// Default repository name
pub const DEFAULT_REPO_NAME: &str = "wasmlabs";
/// Default repository URL
pub const DEFAULT_REPO_URL: &str = "https://workers.wasmlabs.dev/repository/v1/index.toml";
/// Config file name
const CONFIG_FILENAME: &str = ".wws.toml";
/// Loads the data from the Project definition file or .wws.toml.
/// This file contains information about the different runtimes
/// required for this project. You can think of those as dependencies.
///
/// If your project requires to run workers using any interpreted
/// language (except Js, which it's embedded), you will need to install
/// a language runtime.
///
/// For reproducibility, this file can be commited to the project
/// repository so other developers can download them directly.
#[derive(Deserialize, Serialize)]
pub struct Config {
/// Version of the .wws file
version: u32,
/// List of repositories
pub repositories: Vec<ConfigRepository>,
}
impl Config {
/// Load the config file if it's present. It not, it will create a
/// new empty config.
pub fn load(project_root: &Path) -> Result<Self> {
let config_path = Self::config_path(project_root);
if config_path.exists() {
toml::from_str(&fs::read_to_string(config_path)?).map_err(|_| {
anyhow!("Error opening the .wws.toml file. The file format is not correct")
})
} else {
Ok(Self::default())
}
}
/// Save a new installed runtime
pub fn save_runtime(&mut self, repo_name: &str, repo_url: &str, runtime: &Runtime) {
let repo = self.repositories.iter_mut().find(|r| r.name == repo_name);
// Shadow to init an empty one if required
match repo {
Some(r) => r.runtimes.push(runtime.clone()),
None => {
let new_repo = ConfigRepository {
name: repo_name.to_string(),
url: repo_url.to_string(),
runtimes: vec![runtime.clone()],
};
self.repositories.push(new_repo);
}
};
}
/// Remove an existing runtime if it's present.
pub fn remove_runtime(&mut self, repository: &str, name: &str, version: &str) {
let repo = self.repositories.iter_mut().find(|r| r.name == repository);
// Shadow to init an empty one if required
if let Some(repo) = repo {
repo.runtimes
.retain(|r| r.name != name && r.version != version);
};
}
/// Get a given runtime from the current configuration if it's available.
pub fn get_runtime(&self, repository: &str, name: &str, version: &str) -> Option<&Runtime> {
let repo = self.repositories.iter().find(|r| r.name == repository);
if let Some(repo) = repo {
repo.runtimes
.iter()
.find(|r| r.name == name && r.version == version)
} else {
None
}
}
/// Check if there're missing runtimes based on the current configuration
pub fn is_missing_any_runtime(&self, project_root: &Path) -> bool {
for repo in &self.repositories {
if repo
.runtimes
.iter()
.any(|r| !check_runtime(project_root, &repo.name, r))
{
return true;
}
}
false
}
/// Write the current configuration into the `.wws.toml` file. It will
/// store it in the project root folder
pub fn save(&self, project_root: &Path) -> Result<()> {
let contents = toml::to_string_pretty(self)?;
fs::write(Self::config_path(project_root), contents)
.map_err(|_| anyhow!("Error saving the .wws.toml file"))
}
/// Retrieve the configuration path from the project root
fn config_path(project_root: &Path) -> PathBuf {
project_root.join(CONFIG_FILENAME)
}
/// Provides a list of all file extensions handled by the runtimes
/// that are currently installed in `project_root`
pub fn get_runtime_extensions(&self, project_root: &Path) -> Vec<String> {
let mut extensions: Vec<String> = vec![String::from("js"), String::from("wasm")];
for repo in &self.repositories {
for runtime in &repo.runtimes {
for ext in &runtime.extensions {
if check_runtime(project_root, &repo.name, runtime) && !extensions.contains(ext)
{
extensions.push(ext.clone());
}
}
}
}
extensions
}
}
impl Default for Config {
// Initialize an empty repository by default
fn default() -> Self {
let new_repo = ConfigRepository {
name: DEFAULT_REPO_NAME.to_string(),
url: DEFAULT_REPO_URL.to_string(),
runtimes: Vec::new(),
};
Self {
version: 1,
repositories: vec![new_repo],
}
}
}
#[derive(Deserialize, Serialize)]
pub struct ConfigRepository {
/// Local name to identify the repository. It avoids collisions when installing
/// language runtimes
pub name: String,
/// Set the url from which this repository was downloaded
url: String,
/// Installed runtimes
pub runtimes: Vec<Runtime>,
}