Skip to content
This repository has been archived by the owner on Mar 25, 2023. It is now read-only.

Implement Versioning #159

Merged
merged 13 commits into from
Apr 21, 2022
7 changes: 4 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ intl-memoizer = "0.5.1"
sha2 = "0.10"
itertools = "0.10.3"
mime_guess = "2"
semver = "1.0.7"

[dev-dependencies]
fbt-lib = "0.1.17"
Expand Down
5 changes: 5 additions & 0 deletions ftd/fpm.ftd
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
-- record package-data:
caption name:
boolean versioned: false
optional body about:
optional string zip:
optional string language:
Expand Down Expand Up @@ -157,6 +158,10 @@ toc-item list children:



-- toc-item list versions:



-- toc-item list language-toc:


Expand Down
87 changes: 53 additions & 34 deletions src/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,33 +46,39 @@ pub async fn build(
);
}

match (
config.package.translation_of.as_ref(),
config.package.translations.has_elements(),
) {
(Some(_), true) => {
// No package can be both a translation of something and has its own
// translations, when building `config` we ensured this was rejected
unreachable!()
}
(Some(original), false) => {
build_with_original(
config,
original,
file,
base_url,
ignore_failed,
&asset_documents,
)
.await
}
(None, false) => {
build_simple(config, file, base_url, ignore_failed, &asset_documents).await
}
(None, true) => {
build_with_translations(config, file, base_url, ignore_failed, &asset_documents).await
}
}?;
if config.package.versioned {
fpm::version::build_version(config, file, base_url, ignore_failed, &asset_documents)
.await?;
} else {
match (
config.package.translation_of.as_ref(),
config.package.translations.has_elements(),
) {
(Some(_), true) => {
// No package can be both a translation of something and has its own
// translations, when building `config` we ensured this was rejected
unreachable!()
}
(Some(original), false) => {
build_with_original(
config,
original,
file,
base_url,
ignore_failed,
&asset_documents,
)
.await
}
(None, false) => {
build_simple(config, file, base_url, ignore_failed, &asset_documents).await
}
(None, true) => {
build_with_translations(config, file, base_url, ignore_failed, &asset_documents)
.await
}
}?;
}

for dep in dependencies {
let static_files = std::collections::BTreeMap::from_iter(
Expand Down Expand Up @@ -162,6 +168,7 @@ async fn build_with_translations(
base_url,
skip_failed,
asset_documents,
None,
)
.await?;
}
Expand Down Expand Up @@ -316,6 +323,7 @@ async fn process_files(
base_url,
skip_failed,
asset_documents,
None,
)
.await?
}
Expand All @@ -333,6 +341,7 @@ pub(crate) async fn process_file(
base_url: &str,
skip_failed: bool,
asset_documents: &std::collections::HashMap<String, String>,
original_id: Option<String>,
) -> fpm::Result<()> {
use std::io::Write;

Expand Down Expand Up @@ -368,7 +377,7 @@ pub(crate) async fn process_file(
}
}
(fpm::File::Static(main_sa), fpm::File::Static(_)) => {
process_static(main_sa, &config.root, package).await?
process_static(main_sa, &config.root, package, original_id).await?
}
(fpm::File::Code(main_doc), fpm::File::Code(fallback_doc)) => {
process_static(
Expand All @@ -378,6 +387,7 @@ pub(crate) async fn process_file(
},
&config.root,
package,
original_id,
)
.await?;
let resp = process_code(
Expand All @@ -402,7 +412,7 @@ pub(crate) async fn process_file(
}
}
(fpm::File::Image(main_doc), fpm::File::Image(fallback_doc)) => {
process_static(main_doc, &config.root, package).await?;
process_static(main_doc, &config.root, package, original_id).await?;
let resp = process_image(
config,
main_doc,
Expand Down Expand Up @@ -491,7 +501,7 @@ pub(crate) async fn process_file(
}
}
}
fpm::File::Static(sa) => process_static(sa, &config.root, package).await?,
fpm::File::Static(sa) => process_static(sa, &config.root, package, original_id).await?,
fpm::File::Markdown(doc) => {
let resp = process_markdown(
config,
Expand All @@ -515,7 +525,7 @@ pub(crate) async fn process_file(
}
}
fpm::File::Image(main_doc) => {
process_static(main_doc, &config.root, package).await?;
process_static(main_doc, &config.root, package, original_id).await?;
let resp = process_image(
config,
main_doc,
Expand Down Expand Up @@ -546,6 +556,7 @@ pub(crate) async fn process_file(
},
&config.root,
package,
original_id,
)
.await?;
let resp = process_code(
Expand Down Expand Up @@ -1218,28 +1229,36 @@ async fn process_static(
sa: &fpm::Static,
base_path: &camino::Utf8Path,
package: &fpm::Package,
original_id: Option<String>,
) -> fpm::Result<()> {
copy_to_build(sa, base_path, package)?;
copy_to_build(sa, base_path, package, &original_id)?;
if let Some(original_package) = package.translation_of.as_ref() {
copy_to_build(sa, base_path, original_package)?;
copy_to_build(sa, base_path, original_package, &original_id)?;
}
return Ok(());

fn copy_to_build(
sa: &fpm::Static,
base_path: &camino::Utf8Path,
package: &fpm::Package,
original_id: &Option<String>,
) -> fpm::Result<()> {
let build_path = base_path
.join(".build")
.join("-")
.join(package.name.as_str());
let original_id = if let Some(id) = original_id {
id.as_str()
} else {
sa.id.as_str()
};

std::fs::create_dir_all(&build_path)?;
if let Some((dir, _)) = sa.id.rsplit_once(std::path::MAIN_SEPARATOR) {
std::fs::create_dir_all(&build_path.join(dir))?;
}
std::fs::copy(
sa.base_path.join(sa.id.as_str()),
sa.base_path.join(original_id),
build_path.join(sa.id.as_str()),
)?;

Expand Down
83 changes: 79 additions & 4 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,15 +334,87 @@ impl Config {
Ok(())
}

pub(crate) async fn get_files(&self, package: &fpm::Package) -> fpm::Result<Vec<fpm::File>> {
let path = if let Some(package_fpm_path) = &package.fpm_path {
pub(crate) async fn get_versions(
&self,
package: &fpm::Package,
) -> fpm::Result<std::collections::HashMap<fpm::Version, Vec<fpm::File>>> {
let path = self.get_root_for_package(package);
let mut ignore_paths = ignore::WalkBuilder::new(&path);
ignore_paths.overrides(fpm::file::package_ignores(package, &path)?);

let mut hash: std::collections::HashMap<fpm::Version, Vec<fpm::File>> =
std::collections::HashMap::new();

let all_files = ignore_paths
.build()
.into_iter()
.flatten()
.map(|x| camino::Utf8PathBuf::from_path_buf(x.into_path()).unwrap()) //todo: improve error message
.collect::<Vec<camino::Utf8PathBuf>>();

for file in all_files {
if file.is_dir() {
continue;
}
let version = get_version(&file, &path)?;
let file = fpm::get_file(
package.name.to_string(),
&file,
&(if version.original.eq("BASE_VERSION") {
path.to_owned()
} else {
path.join(&version.original)
}),
)
.await?;
if let Some(files) = hash.get_mut(&version) {
files.push(file)
} else {
hash.insert(version, vec![file]);
}
}
return Ok(hash);

fn get_version(
x: &camino::Utf8PathBuf,
path: &camino::Utf8PathBuf,
) -> fpm::Result<fpm::Version> {
let id = match std::fs::canonicalize(x)?.to_str().unwrap().rsplit_once(
if path.as_str().ends_with(std::path::MAIN_SEPARATOR) {
path.as_str().to_string()
} else {
format!("{}{}", path, std::path::MAIN_SEPARATOR)
}
.as_str(),
) {
Some((_, id)) => id.to_string(),
None => {
return Err(fpm::Error::UsageError {
message: format!("{:?} should be a file", x),
});
}
};
if let Some((v, _)) = id.split_once('/') {
fpm::Version::parse(v)
} else {
Ok(fpm::Version::base())
}
}
}

pub(crate) fn get_root_for_package(&self, package: &fpm::Package) -> camino::Utf8PathBuf {
if let Some(package_fpm_path) = &package.fpm_path {
// TODO: Unwrap?
package_fpm_path.parent().unwrap().to_owned()
} else if package.name.eq(&self.package.name) {
self.root.clone()
} else {
self.packages_root.clone().join(package.name.as_str())
};
}
}

pub(crate) async fn get_files(&self, package: &fpm::Package) -> fpm::Result<Vec<fpm::File>> {
let path = self.get_root_for_package(package);
let mut ignore_paths = ignore::WalkBuilder::new(&path);
// ignore_paths.hidden(false); // Allow the linux hidden files to be evaluated
ignore_paths.overrides(fpm::file::package_ignores(package, &path)?);
Expand Down Expand Up @@ -473,6 +545,7 @@ pub(crate) fn find_root_for_file(
#[derive(serde::Deserialize, Debug, Clone)]
pub(crate) struct PackageTemp {
pub name: String,
pub versioned: bool,
#[serde(rename = "translation-of")]
pub translation_of: Option<String>,
#[serde(rename = "translation")]
Expand Down Expand Up @@ -502,6 +575,7 @@ impl PackageTemp {

fpm::Package {
name: self.name,
versioned: self.versioned,
translation_of: Box::new(translation_of),
translations,
language: self.language,
Expand All @@ -522,6 +596,7 @@ impl PackageTemp {
#[derive(Debug, Clone)]
pub struct Package {
pub name: String,
pub versioned: bool,
pub translation_of: Box<Option<Package>>,
pub translations: Vec<Package>,
pub language: Option<String>,
Expand All @@ -541,14 +616,14 @@ pub struct Package {
///
/// Note that this too is kind of bad design, we will move fonts to `fpm::Package` struct soon.
pub fonts: Vec<fpm::Font>,

pub import_auto_imports_from_original: bool,
}

impl Package {
pub fn new(name: &str) -> fpm::Package {
fpm::Package {
name: name.to_string(),
versioned: false,
translation_of: Box::new(None),
translations: vec![],
language: None,
Expand Down
9 changes: 9 additions & 0 deletions src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ impl File {
Self::Image(a) => a.id.clone(),
}
}
pub fn set_id(&mut self, new_id: &str) {
*(match self {
Self::Ftd(a) => &mut a.id,
Self::Static(a) => &mut a.id,
Self::Markdown(a) => &mut a.id,
Self::Code(a) => &mut a.id,
Self::Image(a) => &mut a.id,
}) = new_id.to_string();
}
pub fn get_base_path(&self) -> String {
match self {
Self::Ftd(a) => a.parent_path.to_string(),
Expand Down
Loading