Skip to content

Commit 66b0120

Browse files
authored
Merge pull request cargo-lambda#71 from cargo-lambda/fix_rename
Copy and delete files in virtual directories
2 parents db77bbc + 4da97d0 commit 66b0120

File tree

11 files changed

+358
-185
lines changed

11 files changed

+358
-185
lines changed

Cargo.lock

Lines changed: 77 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cargo-lambda-build/src/lib.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
use cargo_lambda_metadata::binary_targets;
1+
use cargo_lambda_metadata::{cargo::binary_targets, fs::rename};
22
use cargo_zigbuild::Build as ZigBuild;
33
use clap::{Args, ValueHint};
44
use miette::{IntoDiagnostic, Result, WrapErr};
55
use std::{
6+
fs::{create_dir_all, read, File},
67
io::Write,
78
path::{Path, PathBuf},
89
};
@@ -162,20 +163,18 @@ impl Build {
162163
let binary = base.join(name);
163164
if binary.exists() {
164165
let bootstrap_dir = lambda_dir.join(name);
165-
std::fs::create_dir_all(&bootstrap_dir).into_diagnostic()?;
166+
create_dir_all(&bootstrap_dir).into_diagnostic()?;
166167
match self.output_format {
167168
OutputFormat::Binary => {
168-
std::fs::rename(binary, bootstrap_dir.join("bootstrap"))
169-
.into_diagnostic()?;
169+
rename(binary, bootstrap_dir.join("bootstrap")).into_diagnostic()?;
170170
}
171171
OutputFormat::Zip => {
172172
let zipped_binary =
173-
std::fs::File::create(bootstrap_dir.join("bootstrap.zip"))
174-
.into_diagnostic()?;
173+
File::create(bootstrap_dir.join("bootstrap.zip")).into_diagnostic()?;
175174
let mut zip = zip::ZipWriter::new(zipped_binary);
176175
zip.start_file("bootstrap", Default::default())
177176
.into_diagnostic()?;
178-
zip.write_all(&std::fs::read(binary).into_diagnostic()?)
177+
zip.write_all(&read(binary).into_diagnostic()?)
179178
.into_diagnostic()?;
180179
zip.finish().into_diagnostic()?;
181180
}

crates/cargo-lambda-metadata/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,7 @@ cargo_metadata = "0.14.2"
2020
miette = "4.3.0"
2121
serde = { version = "1.0.136", features = ["derive"] }
2222
serde_json = "1.0.79"
23+
24+
[target.'cfg(target_os = "linux")'.dependencies]
25+
libc = "0.2.123"
26+
remove_dir_all = "0.7.0"
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
use cargo_metadata::Metadata as CargoMetadata;
2+
use miette::{IntoDiagnostic, Result, WrapErr};
3+
use serde::Deserialize;
4+
use std::{
5+
collections::{HashMap, HashSet},
6+
path::PathBuf,
7+
};
8+
9+
#[derive(Default, Deserialize)]
10+
#[non_exhaustive]
11+
pub struct Metadata {
12+
#[serde(default)]
13+
pub lambda: LambdaMetadata,
14+
}
15+
16+
#[derive(Clone, Default, Deserialize)]
17+
#[non_exhaustive]
18+
pub struct LambdaMetadata {
19+
#[serde(default)]
20+
pub env: HashMap<String, String>,
21+
#[serde(default)]
22+
pub bin: HashMap<String, PackageMetadata>,
23+
}
24+
25+
#[derive(Clone, Default, Deserialize)]
26+
#[non_exhaustive]
27+
pub struct PackageMetadata {
28+
#[serde(default)]
29+
pub env: HashMap<String, String>,
30+
}
31+
32+
/// Extract all the binary target names from a Cargo.toml file
33+
pub fn binary_targets(manifest_path: PathBuf) -> Result<HashSet<String>> {
34+
let metadata = load_metadata(manifest_path)?;
35+
36+
let bins = metadata
37+
.packages
38+
.iter()
39+
.flat_map(|p| {
40+
p.targets
41+
.iter()
42+
.filter(|target| target.kind.iter().any(|k| k == "bin"))
43+
})
44+
.map(|target| target.name.clone())
45+
.collect::<_>();
46+
47+
Ok(bins)
48+
}
49+
50+
/// Return the lambda metadata section for a function
51+
/// See the documentation to learn about how we use this metadata:
52+
/// https://github.com/cargo-lambda/cargo-lambda#start---environment-variables
53+
pub fn function_metadata(manifest_path: PathBuf, name: &str) -> Result<Option<PackageMetadata>> {
54+
let metadata = match package_metadata(manifest_path, name)? {
55+
None => return Ok(None),
56+
Some(m) => m,
57+
};
58+
59+
let mut env = HashMap::new();
60+
env.extend(metadata.lambda.env);
61+
if let Some(bin) = metadata.lambda.bin.get(name) {
62+
env.extend(bin.env.clone());
63+
}
64+
65+
Ok(Some(PackageMetadata { env }))
66+
}
67+
68+
/// Create metadata about the root package in the Cargo manifest, without any dependencies.
69+
fn load_metadata(manifest_path: PathBuf) -> Result<CargoMetadata> {
70+
let mut metadata_cmd = cargo_metadata::MetadataCommand::new();
71+
metadata_cmd.no_deps();
72+
metadata_cmd.manifest_path(manifest_path);
73+
metadata_cmd.exec().into_diagnostic()
74+
}
75+
76+
// Find the package in the Cargo manifest that contains a binary `name`.
77+
fn package_metadata(manifest_path: PathBuf, name: &str) -> Result<Option<Metadata>> {
78+
let metadata = load_metadata(manifest_path)?;
79+
for pkg in metadata.packages {
80+
for target in &pkg.targets {
81+
if target.name == name && target.kind.iter().any(|kind| kind == "bin") {
82+
let metadata: Metadata = serde_json::from_value(pkg.metadata.clone())
83+
.into_diagnostic()
84+
.wrap_err("invalid lambda metadata in Cargo.toml file")?;
85+
return Ok(Some(metadata));
86+
}
87+
}
88+
}
89+
Ok(None)
90+
}
91+
92+
#[cfg(test)]
93+
mod tests {
94+
use super::*;
95+
96+
fn fixture(name: &str) -> PathBuf {
97+
format!("../../test/fixtures/{name}/Cargo.toml").into()
98+
}
99+
100+
#[test]
101+
fn test_binary_packages() {
102+
let bins = binary_targets(fixture("single-binary-package")).unwrap();
103+
assert_eq!(1, bins.len());
104+
assert!(bins.contains("basic-lambda"));
105+
}
106+
107+
#[test]
108+
fn test_binary_packages_with_mutiple_bin_entries() {
109+
let bins = binary_targets(fixture("multi-binary-package")).unwrap();
110+
assert_eq!(5, bins.len());
111+
assert!(bins.contains("delete-product"));
112+
assert!(bins.contains("get-product"));
113+
assert!(bins.contains("get-products"));
114+
assert!(bins.contains("put-product"));
115+
assert!(bins.contains("dynamodb-streams"));
116+
}
117+
118+
#[test]
119+
fn test_binary_packages_with_workspace() {
120+
let bins = binary_targets(fixture("workspace-package")).unwrap();
121+
assert_eq!(2, bins.len());
122+
assert!(bins.contains("basic-lambda-1"));
123+
assert!(bins.contains("basic-lambda-2"));
124+
}
125+
126+
#[test]
127+
fn test_binary_packages_with_missing_binary_info() {
128+
let err = binary_targets(fixture("missing-binary-package")).unwrap_err();
129+
assert!(err
130+
.to_string()
131+
.contains("a [lib] section, or [[bin]] section must be present"));
132+
}
133+
134+
#[test]
135+
fn test_metadata_packages() {
136+
let meta = function_metadata(fixture("single-binary-package"), "basic-lambda")
137+
.unwrap()
138+
.unwrap();
139+
140+
assert_eq!("BAR", meta.env["FOO"]);
141+
}
142+
143+
#[test]
144+
fn test_metadata_multi_packages() {
145+
let meta = function_metadata(fixture("multi-binary-package"), "get-product")
146+
.unwrap()
147+
.unwrap();
148+
149+
assert_eq!("BAR", meta.env["FOO"]);
150+
151+
let meta = function_metadata(fixture("multi-binary-package"), "delete-product")
152+
.unwrap()
153+
.unwrap();
154+
155+
assert_eq!("QUX", meta.env["BAZ"]);
156+
}
157+
158+
#[test]
159+
fn test_metadata_workspace_packages() {
160+
let meta = function_metadata(fixture("workspace-package"), "basic-lambda-1")
161+
.unwrap()
162+
.unwrap();
163+
164+
assert_eq!("BAR", meta.env["FOO"]);
165+
166+
let meta = function_metadata(fixture("workspace-package"), "basic-lambda-2")
167+
.unwrap()
168+
.unwrap();
169+
170+
assert_eq!("BAR", meta.env["FOO"]);
171+
}
172+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#[cfg(not(target_os = "linux"))]
2+
pub use std::fs::rename;
3+
4+
#[cfg(target_os = "linux")]
5+
mod rename_linux;
6+
#[cfg(target_os = "linux")]
7+
pub use rename_linux::*;

0 commit comments

Comments
 (0)