Skip to content

Commit

Permalink
Extend settings with more customization options
Browse files Browse the repository at this point in the history
Signed-off-by: Sergio Castaño Arteaga <[email protected]>
  • Loading branch information
tegioz committed Aug 30, 2023
1 parent 909cb27 commit 588503f
Show file tree
Hide file tree
Showing 4 changed files with 280 additions and 75 deletions.
190 changes: 131 additions & 59 deletions docs/config/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,77 @@
#
# This settings file allows customizing some aspects of the landscape.

# Groups (optional)
# Foundation (required)
#
# In some cases, specially when a landscape contains lots of items, it may be
# interesting to organize them in groups. Each group will be displayed on a
# different tab in the landscape web application. Each entry must contain the
# name of the group (it will be displayed as is) and a list with the categories
# (as defined in the landscape.yml data file) that will be part of this group.
# Name of the foundation. This value is used in some labels, so we recommended
# to keep it as short as possible.
#
# groups:
# - name: <GROUP_NAME>
# categories:
# - <CATEGORY1_NAME>
# - <CATEGORY2_NAME>
# foundation: <FOUNDATION_NAME>
#
groups:
- name: Projects and products
categories:
- App Definition and Development
- Orchestration & Management
- Runtime
- Provisioning
- Observability and Analysis
- Serverless
- Wasm
- name: Members
categories:
- CNCF Members
- name: Certified partners and providers
categories:
- Platform
- Special
foundation: CNCF

# Name of the members category (optional)
# Logos (required)
#
# Landscapes usually have a special category dedicated to the members of the
# corresponding foundation. It is possible to use any name for that category,
# but it is important that we define it here as there are some special
# operations that depend on it.
# Urls of the logos images used in the landscape UI.
#
# members_category: <CATEGORY_NAME>
# logos:
# header: <HEADER_LOGO_URL>
# footer: <FOOTER_LOGO_URL>
#
members_category: CNCF Members
logos:
header: https://raw.githubusercontent.com/cncf/artwork/master/other/cncf-landscape/horizontal/color/cncf-landscape-horizontal-color.svg
footer: https://raw.githubusercontent.com/cncf/artwork/master/other/cncf/horizontal/white/cncf-white.svg

# Categories (optional)
#
# Categories information is read from the `landscape.yml` data file. The way
# categories are displayed in the web application is computed dynamically based
# on the number of categories and subcategories, as well as the number of items
# on each. Sometimes, however, we may want subcategories to be displayed in a
# specific order within a category (this happens often in the Members category).
# In those cases, it is possible to define that order by overriding a category.
#
# This option can also be used to not display one or more subcategories in the
# landscape. To achieve that, we only need to exclude the subcategory from the
# subcategories list when overriding a category.
#
# categories:
# - name: <CATEGORY_NAME>
# subcategories:
# - <SUBCATEGORY1_NAME>
# - <SUBCATEGORY2_NAME>
#
categories:
- name: CNCF Members
subcategories:
- Platinum
- Gold
- Silver
- End User Supporter
- Nonprofit
- Academic

# Colors (optional)
#
# Colors used across the landscape UI. The colors section is optional but, when
# provided, *all colors must be provided*. Colors must be specified using the
# following format: "rgba(<RED>, <GREEN>, <BLUE>, <ALPHA>)".
#
# colors:
# color1: <COLOR1> # Buttons, groups, links
# color2: <COLOR2> # Some highlighted items like filters button, search icon
# color3: <COLOR3> # Participation stats bars, spinners, modal titles
# color4: <COLOR4> # Categories titles in filters, fieldset in filters modal
# color4: <COLOR5> # Categories and subcategories frames (odd)
# color5: <COLOR6> # Categories and subcategories frames (even)
#
colors:
color1: "rgba(0, 107, 204, 1)"
color2: "rgba(255, 0, 170, 1)"
color3: "rgba(96, 149, 214, 1)"
color4: "rgba(0, 42, 81, 0.7)"
color5: "rgba(1, 107, 204, 0.7)"
color6: "rgba(0, 42, 81, 0.7)"

# Featured items (optional)
#
Expand Down Expand Up @@ -81,31 +110,74 @@ featured_items:
- value: Platinum
- value: Gold

# Overriden categories (optional)
# Groups (optional)
#
# Categories information is read from the `landscape.yml` data file. The way
# categories are displayed in the web application is computed dynamically based
# on the number of categories and subcategories, as well as the number of items
# on each. Sometimes, however, we may want subcategories to be displayed in a
# specific order within a category (this happens often in the Members category).
# In those cases, it is possible to define that order by overriding a category.
# In some cases, specially when a landscape contains lots of items, it may be
# interesting to organize them in groups. Each group will be displayed on a
# different tab in the landscape web application. Each entry must contain the
# name of the group (it will be displayed as is) and a list with the categories
# (as defined in the landscape.yml data file) that will be part of this group.
#
# This option can also be used to not display one or more subcategories in the
# landscape. To achieve that, we only need to exclude the subcategory from the
# subcategories list when overriding a category.
# groups:
# - name: <GROUP_NAME>
# categories:
# - <CATEGORY1_NAME>
# - <CATEGORY2_NAME>
#
# categories:
# - name: <CATEGORY_NAME>
# subcategories:
# - <SUBCATEGORY1_NAME>
# - <SUBCATEGORY2_NAME>
groups:
- name: Projects and products
categories:
- App Definition and Development
- Orchestration & Management
- Runtime
- Provisioning
- Observability and Analysis
- Serverless
- Wasm
- name: Members
categories:
- CNCF Members
- name: Certified partners and providers
categories:
- Platform
- Special

# Name of the members category (optional)
#
categories:
- name: CNCF Members
subcategories:
- Platinum
- Gold
- Silver
- End User Supporter
- Nonprofit
- Academic
# Landscapes usually have a special category dedicated to the members of the
# corresponding foundation. It is possible to use any name for that category,
# but it is important that we define it here as there are some special
# operations that depend on it.
#
# members_category: <CATEGORY_NAME>
#
members_category: CNCF Members

# Social networks urls (optional)
#
# List of social networks urls that will be used to create some links in the
# landscape web application.
#
# social_networks:
# facebook: <FACEBOOK_URL>
# flickr: <FLICKR_URL>
# github: <GITHUB_URL>
# instagram: <INSTAGRAM_URL>
# linkedin: <LINKEDIN_URL>
# slack: <SLACK_URL>
# twitch: <TWITCH_URL>
# twitter: <TWITTER_URL>
# wechat: <WECHAT_URL>
# youtube: <YOUTUBE_URL>
#
social_networks:
facebook: "https://www.facebook.com/CloudNativeComputingFoundation/"
flickr: "https://www.flickr.com/photos/143247548@N03/albums"
github: "https://github.com/cncf"
instagram: "https://www.instagram.com/humans.of.cloudnative/"
linkedin: "https://www.linkedin.com/company/cloud-native-computing-foundation/"
slack: "https://slack.cncf.io/"
twitch: "https://www.twitch.tv/cloudnativefdn"
twitter: "https://twitter.com/cloudnativefdn"
wechat: "https://www.cncf.io/wechat/"
youtube: "https://www.youtube.com/c/cloudnativefdn"
74 changes: 65 additions & 9 deletions src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ use crate::{
guide::LandscapeGuide,
logos::prepare_logo,
projects::{generate_projects_csv, Project, ProjectsMd},
settings::LandscapeSettings,
settings::{LandscapeSettings, Logos},
BuildArgs, GuideSource, LogosSource,
};
use anyhow::{format_err, Result};
use anyhow::{format_err, Context, Result};
use askama::Template;
use futures::stream::{self, StreamExt};
use reqwest::StatusCode;
use rust_embed::RustEmbed;
use std::{
collections::HashMap,
Expand All @@ -27,6 +28,7 @@ use std::{
time::Instant,
};
use tracing::{debug, error, info, instrument};
use url::Url;
use uuid::Uuid;

/// Path where the datasets will be written to in the output directory.
Expand All @@ -35,7 +37,10 @@ const DATASETS_PATH: &str = "data";
/// Path where some documents will be written to in the output directory.
const DOCS_PATH: &str = "docs";

/// Path where the logos will be written to in the output directory.
/// Path where some images will be written to in the output directory.
const IMGS_PATH: &str = "imgs";

/// Path where the item logos will be written to in the output directory.
const LOGOS_PATH: &str = "logos";

/// Maximum number of logos to prepare concurrently.
Expand Down Expand Up @@ -66,17 +71,20 @@ pub(crate) async fn build(args: &BuildArgs) -> Result<()> {
let mut landscape_data = LandscapeData::new(&args.data_source).await?;

// Get landscape settings from the source provided
let settings = LandscapeSettings::new(&args.settings_source).await?;
let mut settings = LandscapeSettings::new(&args.settings_source).await?;

// Add some extra information to the landscape based on the settings
landscape_data.add_featured_items_data(&settings)?;
landscape_data.add_member_subcategory(&settings.members_category);

// Get settings logos and update their urls to the local copy
settings.logos = get_settings_logos(&settings, &args.output_dir).await?;

// Prepare guide and copy it to the output directory
let includes_guide = prepare_guide(&args.guide_source, &args.output_dir).await?.is_some();

// Prepare logos and copy them to the output directory
prepare_logos(&cache, &args.logos_source, &mut landscape_data, &args.output_dir).await?;
// Prepare items logos and copy them to the output directory
prepare_items_logos(&cache, &args.logos_source, &mut landscape_data, &args.output_dir).await?;

// Collect data from external services
let (crunchbase_data, github_data) = tokio::try_join!(
Expand Down Expand Up @@ -190,6 +198,49 @@ fn generate_projects_files(landscape_data: &LandscapeData, output_dir: &Path) ->
Ok(())
}

/// Get settings logos and copy them to the output directory.
#[instrument(skip_all, err)]
async fn get_settings_logos(settings: &LandscapeSettings, output_dir: &Path) -> Result<Logos> {
// Helper closure to process a logo
async fn process_logo(url: &str, output_dir: &Path) -> Result<String> {
// Fetch logo from url
let resp = reqwest::get(url).await?;
if resp.status() != StatusCode::OK {
return Err(format_err!(
"unexpected status ({}) code getting logo {url}",
resp.status()
));
}
let data = resp.bytes().await?.to_vec();

// Write logo to output dir
let url = Url::parse(url).context("invalid logo url")?;
let Some(file_name) = url.path_segments().and_then(Iterator::last) else {
return Err(format_err!("invalid logo url: {url}"));
};
let path = output_dir.join(IMGS_PATH).join(file_name);
let mut file = fs::File::create(&path)?;
file.write_all(&data)?;

Ok(path.to_string_lossy().into_owned())
}

debug!("getting settings logos");
let mut logos = Logos::default();

// Header logo
if let Some(url) = &settings.logos.header {
logos.header = Some(process_logo(url, output_dir).await?);
}

// Footer logo
if let Some(url) = &settings.logos.footer {
logos.footer = Some(process_logo(url, output_dir).await?);
}

Ok(logos)
}

/// Prepare guide and copy it to the output directory.
#[instrument(skip_all, err)]
async fn prepare_guide(guide_source: &GuideSource, output_dir: &Path) -> Result<Option<()>> {
Expand All @@ -204,10 +255,10 @@ async fn prepare_guide(guide_source: &GuideSource, output_dir: &Path) -> Result<
Ok(Some(()))
}

/// Prepare logos and copy them to the output directory, updating the logo
/// reference on each landscape item.
/// Prepare items logos and copy them to the output directory, updating the
/// logo reference on each landscape item.
#[instrument(skip_all, err)]
async fn prepare_logos(
async fn prepare_items_logos(
cache: &Cache,
logos_source: &LogosSource,
landscape_data: &mut LandscapeData,
Expand Down Expand Up @@ -318,6 +369,11 @@ fn setup_output_dir(output_dir: &Path) -> Result<()> {
fs::create_dir(docs_path)?;
}

let imgs_path = output_dir.join(IMGS_PATH);
if !imgs_path.exists() {
fs::create_dir(imgs_path)?;
}

let logos_path = output_dir.join(LOGOS_PATH);
if !logos_path.exists() {
fs::create_dir(logos_path)?;
Expand Down
17 changes: 15 additions & 2 deletions src/datasets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,24 +38,33 @@ impl Datasets {
mod base {
use crate::{
data::{Category, CategoryName, ItemFeatured, LandscapeData, Maturity},
settings::{Group, LandscapeSettings},
settings::{Colors, Group, LandscapeSettings, Logos, SocialNetworks},
};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub(crate) struct Base {
pub foundation: String,
pub logos: Logos,

#[serde(skip_serializing_if = "Vec::is_empty")]
pub categories: Vec<Category>,

#[serde(skip_serializing_if = "Vec::is_empty")]
pub categories_overridden: Vec<CategoryName>,

#[serde(skip_serializing_if = "Option::is_none")]
pub colors: Option<Colors>,

#[serde(skip_serializing_if = "Vec::is_empty")]
pub groups: Vec<Group>,

#[serde(skip_serializing_if = "Vec::is_empty")]
pub items: Vec<Item>,

#[serde(skip_serializing_if = "Option::is_none")]
pub social_networks: Option<SocialNetworks>,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
Expand All @@ -78,8 +87,12 @@ mod base {
/// Create a new Base instance from the data and settings provided.
pub(crate) fn new(landscape_data: &LandscapeData, settings: &LandscapeSettings) -> Self {
let mut base = Base {
groups: settings.groups.clone().unwrap_or(vec![]),
foundation: settings.foundation.clone(),
logos: settings.logos.clone(),
categories: landscape_data.categories.clone(),
colors: settings.colors.clone(),
groups: settings.groups.clone().unwrap_or(vec![]),
social_networks: settings.social_networks.clone(),
..Default::default()
};

Expand Down
Loading

0 comments on commit 588503f

Please sign in to comment.