-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathcmd_make_source.rs
158 lines (137 loc) · 5.2 KB
/
cmd_make_source.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
// Copyright (c) Contributors to the SPK project.
// SPDX-License-Identifier: Apache-2.0
// https://github.com/spkenv/spk
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::sync::Arc;
use clap::Args;
use miette::{bail, Context, Result};
use spk_build::SourcePackageBuilder;
use spk_cli_common::{flags, BuildArtifact, BuildResult, CommandArgs, Run};
use spk_schema::foundation::format::FormatIdent;
use spk_schema::ident::LocatedBuildIdent;
use spk_schema::v0::Spec;
use spk_schema::{
AnyIdent,
Lint,
LintedItem,
Package,
Recipe,
SpecTemplate,
Template,
TemplateExt,
};
use spk_storage as storage;
/// Build a source package from a spec file.
#[derive(Args)]
#[clap(visible_aliases = &["mksource", "mksrc", "mks"])]
pub struct MakeSource {
#[clap(flatten)]
pub runtime: flags::Runtime,
#[clap(flatten)]
pub options: flags::Options,
#[clap(short, long, global = true, action = clap::ArgAction::Count)]
pub verbose: u8,
/// The packages or yaml spec files to collect
#[clap(name = "PKG|SPEC_FILE")]
pub packages: Vec<String>,
/// Populated with the created src to generate a summary from the caller.
#[clap(skip)]
pub created_src: BuildResult,
/// Used to gather lints to output at the end of a build.
#[clap(skip)]
pub lints: BTreeMap<String, Vec<Lint>>,
}
#[async_trait::async_trait]
impl Run for MakeSource {
type Output = i32;
async fn run(&mut self) -> Result<Self::Output> {
self.make_source().await.map(|_| 0)
}
}
impl MakeSource {
pub async fn make_source(&mut self) -> Result<Vec<LocatedBuildIdent>> {
if spfs::get_config()?
.storage
.allow_payload_sharing_between_users
{
bail!(
"Building packages disabled when 'allow_payload_sharing_between_users' is enabled"
);
}
let _runtime = self
.runtime
.ensure_active_runtime(&["make-source", "mksource", "mksrc", "mks"])
.await?;
let local: storage::RepositoryHandle = storage::local_repository().await?.into();
let options = self.options.get_options()?;
let mut packages: Vec<_> = self.packages.iter().cloned().map(Some).collect();
if packages.is_empty() {
packages.push(None)
}
let mut idents = Vec::new();
for package in packages.into_iter() {
let template = match flags::find_package_template(package.as_ref())? {
flags::FindPackageTemplateResult::NotFound(name) => {
// TODO:: load from given repos
Arc::new(SpecTemplate::from_file(name.as_ref())?)
}
res => {
let (_, template) = res.must_be_found();
template
}
};
let root = template
.file_path()
.parent()
.map(ToOwned::to_owned)
.unwrap_or_else(|| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")));
if let Some(name) = template.name() {
tracing::info!("rendering template for {name}");
} else {
tracing::info!("rendering template without a name");
}
let rendered_data = template.render(&options)?;
let recipe = rendered_data.into_recipe().wrap_err_with(|| {
format!(
"{filename} was expected to contain a recipe",
filename = template.file_path().to_string_lossy()
)
})?;
let ident = recipe.ident();
let lints: std::result::Result<LintedItem<Spec<AnyIdent>>, serde_yaml::Error> =
serde_yaml::from_str(&template.render_to_string(&options)?);
match lints {
Ok(linted_item) => match linted_item.lints.is_empty() {
true => (),
false => {
self.lints
.insert(ident.format_ident(), linted_item.lints.clone());
}
},
Err(e) => tracing::error!("Failed to retrieve lints: {e}"),
}
tracing::info!("saving package recipe for {}", ident.format_ident());
local.force_publish_recipe(&recipe).await?;
tracing::info!("collecting sources for {}", ident.format_ident());
let (out, _components) =
SourcePackageBuilder::from_recipe(Arc::unwrap_or_clone(recipe))
.build_and_publish(root, &local)
.await
.wrap_err("Failed to collect sources")?;
tracing::info!("created {}", out.ident().format_ident());
self.created_src.push(
template.file_path().display().to_string(),
BuildArtifact::Source(out.ident().clone()),
);
idents.push(out.ident().clone().into_located(local.name().to_owned()));
}
Ok(idents)
}
}
impl CommandArgs for MakeSource {
fn get_positional_args(&self) -> Vec<String> {
// The important positional args for a make-source are the packages
self.packages.clone()
}
}