Skip to content

Commit

Permalink
Merge branch 'main' into issues/195-python
Browse files Browse the repository at this point in the history
  • Loading branch information
gadomski authored Oct 18, 2023
2 parents 19807c1 + a129960 commit 3b14b7b
Show file tree
Hide file tree
Showing 15 changed files with 316 additions and 48 deletions.
7 changes: 4 additions & 3 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
4. Update the package's `Cargo.toml` file accordingly, and update the other packages' `Cargo.toml` if they depend on this package.
5. Scan the package's README for references to version numbers, and update any that are needed.
6. Update the package's CHANGELOG with a new section for the new version. Don't forget to update the links at the bottom, too.
7. Test the release with `cargo release -p {package name}`. By default, this does a dry-run, so it won't actually do anything.
8. Use the normal pull request workflow to merge your branch.
9. Once merged, run `cargo release --execute` to do the release. Use the same `-p` flags as you did during the dry run.
7. If it's a breaking release, search for any deprecated functions that should be removed.
8. Test the release with `cargo release -p {package name}`. By default, this does a dry-run, so it won't actually do anything.
9. Use the normal pull request workflow to merge your branch.
10. Once merged, run `cargo release --execute` to do the release. Use the same `-p` flags as you did during the dry run.

## After-the-fact releases

Expand Down
4 changes: 4 additions & 0 deletions stac-api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

### Added

- `Search.validate` ([#206](https://github.com/stac-utils/stac-rs/pull/206))

## [0.3.2] - 2023-10-11

### Added
Expand Down
5 changes: 5 additions & 0 deletions stac-api/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::Search;
use serde_json::{Map, Value};
use thiserror::Error;

Expand All @@ -23,6 +24,10 @@ pub enum Error {
#[error(transparent)]
ParseFloatError(#[from] std::num::ParseFloatError),

/// A search has both bbox and intersects.
#[error("search has bbox and intersects")]
SearchHasBboxAndIntersects(Search),

/// [serde_json::Error]
#[error(transparent)]
SerdeJson(#[from] serde_json::Error),
Expand Down
23 changes: 23 additions & 0 deletions stac-api/src/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,29 @@ pub struct GetSearch {
pub additional_fields: HashMap<String, String>,
}

impl Search {
/// Validates this search.
///
/// E.g. the search is invalid if both bbox and intersects are specified.
///
/// # Examples
///
/// ```
/// use stac_api::Search;
/// let mut search = Search { bbox: Some(vec![-180.0, -90.0, 180.0, 80.0]), ..Default::default() };
/// search.validate().unwrap();
/// search.intersects = Some(stac::Geometry::point(0., 0.));
/// let _ = search.validate().unwrap_err();
/// ```
pub fn validate(&self) -> Result<()> {
if self.bbox.is_some() & self.intersects.is_some() {
Err(Error::SearchHasBboxAndIntersects(self.clone()))
} else {
Ok(())
}
}
}

impl TryFrom<Search> for GetSearch {
type Error = Error;

Expand Down
9 changes: 8 additions & 1 deletion stac-cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

## [0.0.6] - 2023-10-18

### Added

- Validation for the collections endpoint ([#208](https://github.com/stac-utils/stac-rs/pull/208))

## [0.0.5] - 2023-10-11

### Added
Expand All @@ -33,7 +39,8 @@ Moved over from [stac-incubator-rs](https://github.com/gadomski/stac-incubator-r
- Downloading ([#142](https://github.com/stac-utils/stac-rs/pull/142), [#152](https://github.com/stac-utils/stac-rs/pull/152))
- Validation ([#155](https://github.com/stac-utils/stac-rs/pull/155))

[Unreleased]: https://github.com/stac-utils/stac-rs/compare/stac-cli-v0.0.5..main
[Unreleased]: https://github.com/stac-utils/stac-rs/compare/stac-cli-v0.0.6..main
[0.0.6]: https://github.com/stac-utils/stac-rs/compare/stac-cli-v0.0.5..stac-cli-v0.0.6
[0.0.5]: https://github.com/stac-utils/stac-rs/compare/stac-cli-v0.0.4..stac-cli-v0.0.5
[0.0.4]: https://github.com/stac-utils/stac-rs/compare/stac-cli-v0.0.3..stac-cli-v0.0.4
[0.0.3]: https://github.com/stac-utils/stac-rs/tree/stac-cli-v0.0.3
2 changes: 1 addition & 1 deletion stac-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "stac-cli"
version = "0.0.5"
version = "0.0.6"
edition = "2021"
description = "Command line interface for stac-rs"
documentation = "https://docs.rs/stac-cli"
Expand Down
10 changes: 8 additions & 2 deletions stac-cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,15 @@ pub enum Command {
compact: bool,
},

/// Validates a STAC object using json-schema validation.
/// Validates a STAC object or API endpoint using json-schema validation.
Validate {
/// The href of the STAC object.
/// The href of the STAC object or endpoint.
///
/// The validator will make some decisions depending on what type of
/// data is returned from the href. If it's a STAC Catalog, Collection,
/// or Item, that object will be validated. If its a collections
/// endpoint from a STAC API, all collections will be validated.
/// Additional behavior TBD.
href: String,
},
}
Expand Down
59 changes: 51 additions & 8 deletions stac-cli/src/commands/validate.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,55 @@
use crate::Result;
use stac_validate::Validate;
use crate::{Error, Result};
use stac_validate::{Validate, Validator};

pub async fn validate(href: &str) -> Result<()> {
let value: serde_json::Value = stac_async::read_json(href).await?;
let result = {
let value = value.clone();
tokio::task::spawn_blocking(move || value.validate()).await?
};
if let Some(map) = value.as_object() {
if map.contains_key("type") {
let value = value.clone();
let result = tokio::task::spawn_blocking(move || value.validate()).await?;
print_result(result).map_err(Error::from)
} else if let Some(collections) = map
.get("collections")
.and_then(|collections| collections.as_array())
{
let collections = collections.clone();
let result = tokio::task::spawn_blocking(move || {
let mut errors = Vec::new();
let mut validator = Validator::new();
let num_collections = collections.len();
let mut valid_collections = 0;
for collection in collections {
if let Some(id) = collection.get("id").and_then(|id| id.as_str()) {
println!("== Validating {}", id);
}
let result = validator.validate(collection);
match print_result(result) {
Ok(()) => valid_collections += 1,
Err(err) => errors.push(err),
}
println!("")
}
println!(
"{}/{} collections are valid",
valid_collections, num_collections
);
if errors.is_empty() {
Ok(())
} else {
Err(Error::ValidationGroup(errors))
}
})
.await?;
result
} else {
todo!()
}
} else {
todo!()
}
}

pub fn print_result(result: stac_validate::Result<()>) -> stac_validate::Result<()> {
match result {
Ok(()) => {
println!("OK!");
Expand All @@ -16,11 +59,11 @@ pub async fn validate(href: &str) -> Result<()> {
for err in &errors {
println!("Validation error at {}: {}", err.instance_path, err)
}
Err(stac_validate::Error::Validation(errors).into())
Err(stac_validate::Error::Validation(errors))
}
Err(err) => {
println!("Error while validating: {}", err);
Err(err.into())
Err(err)
}
}
}
3 changes: 3 additions & 0 deletions stac-cli/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ pub enum Error {

#[error(transparent)]
TokioJoinError(#[from] tokio::task::JoinError),

#[error("many validation errors")]
ValidationGroup(Vec<stac_validate::Error>),
}

impl Error {
Expand Down
18 changes: 17 additions & 1 deletion stac/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

### Added

- `Geometry::point` ([#206](https://github.com/stac-utils/stac-rs/pull/206))

## [0.5.2] - 2023-10-18

### Added

- `Item.intersects` ([#202](https://github.com/stac-utils/stac-rs/pull/202))
- Common metadata fields ([#203](https://github.com/stac-utils/stac-rs/pull/203))

### Deprecated

- `Item.intersects_bbox` ([#204](https://github.com/stac-utils/stac-rs/pull/204))

## [0.5.1] - 2023-09-14

### Added
Expand Down Expand Up @@ -239,7 +254,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

Initial release.

[Unreleased]: https://github.com/stac-utils/stac-rs/compare/stac-v0.5.1...main
[Unreleased]: https://github.com/stac-utils/stac-rs/compare/stac-v0.5.2...main
[0.5.2]: https://github.com/stac-utils/stac-rs/compare/stac-v0.5.1...stac-v0.5.2
[0.5.1]: https://github.com/stac-utils/stac-rs/compare/stac-v0.5.0...stac-v0.5.1
[0.5.0]: https://github.com/stac-utils/stac-rs/compare/stac-v0.4.0...stac-v0.5.0
[0.4.0]: https://github.com/stac-utils/stac-rs/compare/stac-v0.3.2...stac-v0.4.0
Expand Down
2 changes: 1 addition & 1 deletion stac/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "stac"
version = "0.5.1"
version = "0.5.2"
authors = ["Pete Gadomski <[email protected]>"]
edition = "2021"
description = "Rust library for the SpatioTemporal Asset Catalog (STAC) specification"
Expand Down
22 changes: 22 additions & 0 deletions stac/src/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,26 @@ pub struct Asset {
#[serde(skip_serializing_if = "Option::is_none")]
pub roles: Option<Vec<String>>,

/// Creation date and time of the corresponding data, in UTC.
///
/// This identifies the creation time of the data.
///
/// This is a [common
/// metadata](https://github.com/radiantearth/stac-spec/blob/master/item-spec/common-metadata.md)
/// field.
#[serde(skip_serializing_if = "Option::is_none")]
pub created: Option<String>,

/// Date and time the metadata was updated last, in UTC.
///
/// This identifies the updated time of the data.
///
/// This is a [common
/// metadata](https://github.com/radiantearth/stac-spec/blob/master/item-spec/common-metadata.md)
/// field.
#[serde(skip_serializing_if = "Option::is_none")]
pub updated: Option<String>,

/// Additional fields on the asset.
#[serde(flatten)]
pub additional_fields: Map<String, Value>,
Expand Down Expand Up @@ -84,6 +104,8 @@ impl Asset {
description: None,
r#type: None,
roles: None,
created: None,
updated: None,
additional_fields: Map::new(),
}
}
Expand Down
67 changes: 67 additions & 0 deletions stac/src/geometry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};

#[cfg(feature = "geo")]
use crate::{Error, Result};

/// Additional metadata fields can be added to the GeoJSON Object Properties.
///
/// We can't just use the [geojson] crate because it doesn't implement [schemars].
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Geometry {
/// The geometry type.
pub r#type: String,

/// The other geometry attributes.
///
/// `GeometryCollection` doesn't have a `coordinates` member, so we must
/// capture everything in a flat, generic array.
#[serde(flatten)]
pub attributes: Map<String, Value>,
}

impl Geometry {
/// Creates a point geometry.
///
/// # Examples
///
/// ```
/// use stac::Geometry;
/// let geometry = Geometry::point(-108.0, 42.0);
/// ```
pub fn point(x: f64, y: f64) -> Geometry {
use serde_json::json;

let mut attributes = Map::new();
let _ = attributes.insert("coordinates".to_string(), json!([x, y]));
Geometry {
r#type: "Point".to_string(),
attributes,
}
}
}

#[cfg(feature = "geo")]
impl TryFrom<Geometry> for geo::Geometry {
type Error = Error;
fn try_from(geometry: Geometry) -> Result<geo::Geometry> {
serde_json::from_value::<geojson::Geometry>(serde_json::to_value(geometry)?)?
.try_into()
.map_err(Error::from)
}
}

#[cfg(test)]
mod tests {
#[test]
#[cfg(feature = "geo")]
fn point() {
let point = super::Geometry::point(-108.0, 42.0);
let geometry: geo::Geometry = point.try_into().unwrap();
assert_eq!(
geometry,
geo::Geometry::Point(geo::Point::new(-108.0, 42.0))
);
}
}
Loading

0 comments on commit 3b14b7b

Please sign in to comment.