Skip to content

Commit 8e3c1c2

Browse files
edwardaleeCopilot
andauthored
Various enhancements to the build process (#65)
* Various enhancements to the build process * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Respond to Copilot review * Tuned README * Removing timing of checksum * Remove cleanall and replace with update * Removed todo which triggers a warning * Format --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 2e799b3 commit 8e3c1c2

8 files changed

Lines changed: 186 additions & 35 deletions

File tree

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ Build system for the Lingua Franca coordination language
1717
Usage: lingo [OPTIONS] <COMMAND>
1818
1919
Commands:
20-
init Initialize a Lingua Franca package
21-
build Compile one or multiple binaries in a Lingua Franca package
22-
update Update the dependencies and potentially build tools
23-
run Build and run binaries
24-
clean Remove build artifacts
25-
help Print this message or the help of the given subcommand(s)
20+
init Initialize a Lingua Franca package
21+
build Compile one or multiple binaries in a Lingua Franca package
22+
update Remove build artifacts, update the dependencies, and build
23+
run Build and run binaries
24+
clean Remove build artifacts
25+
help Print this message or the help of the given subcommand(s)
2626
2727
Options:
2828
-q, --quiet Do not produce any output

src/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ General workflow that is happening.
66

77
```mermaid
88
graph TD
9-
A[Start] --> B(Handeling User Input)
9+
A[Start] --> B(Handling User Input)
1010
B --> C(Parsing Lingo.toml)
1111
C --> D(Configuring LFC)
1212
D --> E(Invoking LFC)

src/backends/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ pub fn execute_command<'a>(
3131

3232
match command {
3333
CommandSpec::Build(_build) => {
34+
log::info!(
35+
"{} starting dependency resolution ({} declared dependencies)",
36+
"Build step:",
37+
dependencies.len()
38+
);
3439
let manager = match DependencyManager::from_dependencies(
3540
dependencies.clone(),
3641
&PathBuf::from(OUTPUT_DIRECTORY),
@@ -44,6 +49,7 @@ pub fn execute_command<'a>(
4449
};
4550

4651
// enriching the apps with the target properties from the libraries
52+
log::info!("Build step: merging dependency target properties");
4753
let library_properties = manager.get_target_properties().expect("lib properties");
4854

4955
// merging app with library target properties
@@ -67,6 +73,12 @@ pub fn execute_command<'a>(
6773
}
6874

6975
for (build_system, apps) in by_build_system {
76+
log::info!(
77+
"Build step: dispatching {} app(s) to {:?}/{:?}",
78+
apps.len(),
79+
build_system.0,
80+
build_system.1
81+
);
7082
let mut sub_res = BatchBuildResults::for_apps(&apps);
7183

7284
sub_res.map(|app| {

src/main.rs

Lines changed: 82 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use liblingo::args::TargetLanguage;
22
use std::io::ErrorKind;
33
use std::path::{Path, PathBuf};
44
use std::process::Command;
5-
use std::{env, io};
5+
use std::{env, fs, io};
66

77
use clap::Parser;
88
use git2::BranchType::{Local, Remote};
@@ -91,10 +91,55 @@ fn do_read_to_string(p: &Path) -> io::Result<String> {
9191
std::fs::read_to_string(p)
9292
}
9393

94+
fn remove_if_exists(path: &Path) -> io::Result<()> {
95+
if path.is_dir() {
96+
match fs::remove_dir_all(path) {
97+
Ok(()) => log::info!("Deleted {}", path.display()),
98+
Err(err) => {
99+
log::error!("Failed to delete {}: {}", path.display(), err);
100+
return Err(err);
101+
}
102+
}
103+
} else if path.is_file() {
104+
match fs::remove_file(path) {
105+
Ok(()) => log::info!("Deleted {}", path.display()),
106+
Err(err) => {
107+
log::error!("Failed to delete {}: {}", path.display(), err);
108+
return Err(err);
109+
}
110+
}
111+
}
112+
Ok(())
113+
}
114+
115+
fn update(project_root: &Path) -> BuildResult {
116+
remove_if_exists(&project_root.join("build"))?;
117+
let lock_path = project_root.join("Lingo.lock");
118+
if lock_path.is_file() {
119+
let backup_path = (0..)
120+
.map(|n| project_root.join(format!("Lingo.lock.bak{}", n)))
121+
.find(|p| !p.exists())
122+
.unwrap();
123+
fs::rename(&lock_path, &backup_path)?;
124+
log::info!("Backed up Lingo.lock to {}", backup_path.display());
125+
}
126+
Ok(())
127+
}
128+
94129
fn main() {
95-
print_logger::new().init().unwrap();
96130
// parses command line arguments
97131
let args = CommandLineArgs::parse();
132+
let level_filter = if args.quiet {
133+
print_logger::LevelFilter::Error
134+
} else if args.verbose {
135+
print_logger::LevelFilter::Debug
136+
} else {
137+
print_logger::LevelFilter::Info
138+
};
139+
print_logger::new()
140+
.level_filter(level_filter)
141+
.init()
142+
.unwrap();
98143

99144
// Finds Lingo.toml recursively inside the parent directories.
100145
// If it exists the returned path is absolute.
@@ -116,6 +161,7 @@ fn main() {
116161
let result = execute_command(
117162
&mut wrapped_config,
118163
args.command,
164+
lingo_path.as_deref(),
119165
Box::new(do_which),
120166
Box::new(do_clone_and_checkout),
121167
);
@@ -161,6 +207,7 @@ fn validate(config: &mut Option<Config>, command: &ConsoleCommand) -> BuildResul
161207
fn execute_command<'a>(
162208
config: &'a mut Option<Config>,
163209
command: ConsoleCommand,
210+
lingo_path: Option<&Path>,
164211
_which_capability: WhichCapability,
165212
git_clone_capability: GitCloneAndCheckoutCap,
166213
) -> CommandResult<'a> {
@@ -187,7 +234,34 @@ fn execute_command<'a>(
187234
(Some(config), ConsoleCommand::Clean) => {
188235
CommandResult::Batch(run_command(CommandSpec::Clean, config, true))
189236
}
190-
_ => todo!(),
237+
(Some(config), ConsoleCommand::Update) => {
238+
let update_result = lingo_path
239+
.and_then(Path::parent)
240+
.ok_or_else(|| {
241+
Box::new(io::Error::new(
242+
ErrorKind::NotFound,
243+
"Error: Missing Lingo.toml file",
244+
)) as Box<dyn std::error::Error + Send + Sync>
245+
})
246+
.and_then(update);
247+
match update_result {
248+
Err(e) => CommandResult::Single(Err(e)),
249+
Ok(()) => {
250+
let default_args = BuildArgs {
251+
build_system: None,
252+
language: None,
253+
platform: None,
254+
lfc: None,
255+
no_compile: false,
256+
keep_going: false,
257+
release: false,
258+
apps: vec![],
259+
threads: 0,
260+
};
261+
CommandResult::Batch(build(&default_args, config))
262+
}
263+
}
264+
}
191265
}
192266
}
193267

@@ -216,7 +290,11 @@ fn build<'a>(args: &BuildArgs, config: &'a mut Config) -> BatchBuildResults<'a>
216290
)
217291
}
218292

219-
fn run_command(task: CommandSpec, config: &mut Config, _fail_at_end: bool) -> BatchBuildResults {
293+
fn run_command(
294+
task: CommandSpec,
295+
config: &mut Config,
296+
_fail_at_end: bool,
297+
) -> BatchBuildResults<'_> {
220298
let _apps = config.apps.iter().collect::<Vec<_>>();
221299
liblingo::backends::execute_command(
222300
&task,

src/package/lock.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use crate::util::sha1dir;
2-
use colored::Colorize;
32
use serde::{Deserialize, Deserializer, Serialize, Serializer};
43
use versions::Versioning;
54

6-
use log::error;
5+
use log::{error, info};
76
use serde::de::Error as DeserializationError;
87
use serde::ser::Error as SerializationError;
98
use std::cmp::PartialEq;
@@ -213,18 +212,32 @@ impl DependencyLock {
213212
lfc_include_folder: &Path,
214213
git_clone_and_checkout_cap: &GitCloneAndCheckoutCap,
215214
) -> anyhow::Result<()> {
215+
info!(
216+
"Build step: checking lock entries in {}",
217+
lfc_include_folder.display()
218+
);
216219
for (_, lock) in self.dependencies.iter() {
217220
let temp = lfc_include_folder.join(&lock.name);
218221
// the Lingo.toml for this dependency doesnt exists, hence we need to fetch this package
219222
if !temp.join("Lingo.toml").exists() {
220223
let mut details = PackageDetails::try_from(&lock.source)?;
224+
info!(
225+
"Fetching {} from {}+{}",
226+
lock.name, lock.source.source_type, lock.source.uri
227+
);
221228

222229
details
223230
.fetch(&temp, git_clone_and_checkout_cap)
224231
.expect("cannot pull package");
225232
}
226233

234+
info!(
235+
"Build step: computing checksum for locked dependency {} at {}",
236+
lock.name,
237+
temp.display()
238+
);
227239
let hash = sha1dir::checksum_current_dir(&temp, false);
240+
info!("Build step: checksum complete for {}", lock.name);
228241

229242
if hash.to_string() != lock.checksum {
230243
error!("checksum does not match aborting!");
@@ -233,12 +246,7 @@ impl DependencyLock {
233246
let lingo_toml_text = fs::read_to_string(temp.join("Lingo.toml"))?;
234247
let read_toml = toml::from_str::<ConfigFile>(&lingo_toml_text)?.to_config(&temp);
235248

236-
println!(
237-
"{} {} ... {}",
238-
"Reading".green().bold(),
239-
lock.name,
240-
read_toml.package.version
241-
);
249+
info!("Reading {} ... {}", lock.name, read_toml.package.version);
242250

243251
let lib = match read_toml.library {
244252
Some(value) => value,

src/package/management.rs

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use colored::Colorize;
2-
use log::error;
1+
use anyhow::Context;
2+
use log::{error, info};
33
use versions::{Requirement, Versioning};
44

55
use crate::util::sha1dir;
@@ -10,6 +10,7 @@ use std::fs::File;
1010
use std::io::Write;
1111
use std::path::{Path, PathBuf};
1212
use std::str::FromStr;
13+
use std::time::Instant;
1314
use url::{ParseError, Url};
1415

1516
use crate::package::lock::{PackageLockSource, PackageLockSourceType};
@@ -75,8 +76,12 @@ impl PackageDetails {
7576
) -> anyhow::Result<()> {
7677
match &self.mutual_exclusive {
7778
ProjectSource::Path(path_buf) => {
78-
let src = fs::canonicalize(path_buf)?;
79-
let dst = fs::canonicalize(library_path)?;
79+
let src = fs::canonicalize(path_buf).with_context(|| {
80+
format!("dependency path not found: {}", path_buf.display())
81+
})?;
82+
let dst = fs::canonicalize(library_path).with_context(|| {
83+
format!("library path not found: {}", library_path.display())
84+
})?;
8085
Ok(copy_dir_all(src, dst)?)
8186
}
8287
ProjectSource::Git(git_url) => {
@@ -98,22 +103,39 @@ impl DependencyManager {
98103
target_path: &Path,
99104
git_clone_and_checkout_cap: &GitCloneAndCheckoutCap,
100105
) -> anyhow::Result<DependencyManager> {
106+
info!(
107+
"Build step: resolving dependencies in {}",
108+
target_path.display()
109+
);
101110
// create library folder
102111
let library_path = target_path.join(LIBRARY_DIRECTORY);
103-
fs::create_dir_all(&library_path)?;
112+
fs::create_dir_all(&library_path).with_context(|| {
113+
format!(
114+
"failed to create library directory: {}",
115+
library_path.display()
116+
)
117+
})?;
104118

105119
let mut manager;
106120
let mut lock: DependencyLock;
107121
let lock_file = target_path.join("../Lingo.lock");
108122

109123
// checks if a Lingo.lock file exists
110124
if lock_file.exists() {
125+
info!("Build step: loading lock file {}", lock_file.display());
111126
// reads and parses Lockfile
112-
lock = toml::from_str::<DependencyLock>(&fs::read_to_string(lock_file)?)
127+
lock =
128+
toml::from_str::<DependencyLock>(&fs::read_to_string(&lock_file).with_context(
129+
|| format!("failed to read lock file: {}", lock_file.display()),
130+
)?)
113131
.expect("cannot parse lock");
114132

115133
// if a lock file is present it will load the dependencies from it and checks
116134
// integrity of the build directory
135+
info!(
136+
"Build step: validating lock dependencies in {}",
137+
target_path.join("lfc_include").display()
138+
);
117139
if let Ok(()) = lock.init(&target_path.join("lfc_include"), git_clone_and_checkout_cap)
118140
{
119141
return Ok(DependencyManager {
@@ -140,9 +162,14 @@ impl DependencyManager {
140162
lock = DependencyLock::create(selection);
141163

142164
// writes the lock file down
143-
let mut lock_file = File::create(target_path.join("../Lingo.lock"))?;
144-
145-
println!("{:?}", lock.dependencies);
165+
let lock_file_path = target_path.join("../Lingo.lock");
166+
let mut lock_file = File::create(&lock_file_path)
167+
.with_context(|| format!("failed to create lock file: {}", lock_file_path.display()))?;
168+
169+
info!(
170+
"Build step: selected lock dependencies: {:?}",
171+
lock.dependencies
172+
);
146173
let serialized_toml = toml::to_string(&lock).expect("cannot generate toml");
147174

148175
lock_file.write_all(serialized_toml.as_ref())?;
@@ -168,11 +195,16 @@ impl DependencyManager {
168195
self.pulling_queue.append(&mut dependencies);
169196
let sub_dependency_path = root_path.join("libraries");
170197
//fs::remove_dir_all(&sub_dependency_path)?;
171-
fs::create_dir_all(&sub_dependency_path)?;
198+
fs::create_dir_all(&sub_dependency_path).with_context(|| {
199+
format!(
200+
"failed to create directory: {}",
201+
sub_dependency_path.display()
202+
)
203+
})?;
172204

173205
while !self.pulling_queue.is_empty() {
174206
if let Some((package_name, package_details)) = self.pulling_queue.pop() {
175-
print!("{} {} ...", "Cloning".green().bold(), package_name);
207+
info!("Cloning {} ...", package_name);
176208
let node = match self.non_recursive_fetching(
177209
&package_name,
178210
package_details,
@@ -216,15 +248,32 @@ impl DependencyManager {
216248
fs::create_dir_all(&temporary_path)?;
217249

218250
// cloning the specified package
251+
info!(
252+
"Build step: fetching dependency {} into {}",
253+
name,
254+
temporary_path.display()
255+
);
219256
package.fetch(&temporary_path, git_clone_and_checkout_cap)?;
220257

258+
info!(
259+
"Build step: computing checksum for {}",
260+
temporary_path.display()
261+
);
262+
let checksum_started_at = Instant::now();
221263
let hash = sha1dir::checksum_current_dir(&temporary_path, false);
264+
info!(
265+
"Build step: checksum complete for {} in {:?}",
266+
temporary_path.display(),
267+
checksum_started_at.elapsed()
268+
);
222269
let include_path = library_path.join(hash.to_string());
223270

224-
let lingo_toml_text = fs::read_to_string(temporary_path.clone().join("Lingo.toml"))?;
271+
let lingo_toml_path = temporary_path.join("Lingo.toml");
272+
let lingo_toml_text = fs::read_to_string(&lingo_toml_path)
273+
.with_context(|| format!("failed to read {}", lingo_toml_path.display()))?;
225274
let read_toml = toml::from_str::<ConfigFile>(&lingo_toml_text)?.to_config(&temporary_path);
226275

227-
println!(" {}", read_toml.package.version);
276+
info!("Resolved dependency version {}", read_toml.package.version);
228277

229278
let config = match read_toml.library {
230279
Some(value) => value,

0 commit comments

Comments
 (0)