From 4cc582e08c6657ad290f2a82872e35361f4ba422 Mon Sep 17 00:00:00 2001 From: jake <77554505+brxken128@users.noreply.github.com> Date: Mon, 20 Feb 2023 05:58:55 +0000 Subject: [PATCH] [ENG-134] OSS Licenses and Projects (#575) * add `deps-generator` crate * move `clap` types to separate file * idiomatic filtering * experimentally update ci * add *really* basic dependency page * remove `license_id` from `License` * add bare minimum JSON files * Revert "experimentally update ci" This reverts commit c04897d902c9a55baf14d532f4590bc711f08c16. * re-insert comments * Using reqwest blocking feature to avoid asyncness --------- Co-authored-by: Ericson Soares --- Cargo.lock | 40 +++++++++- crates/deps-generator/Cargo.toml | 14 ++++ crates/deps-generator/src/main.rs | 75 +++++++++++++++++++ crates/deps-generator/src/types/backend.rs | 12 +++ crates/deps-generator/src/types/cli.rs | 33 ++++++++ crates/deps-generator/src/types/frontend.rs | 36 +++++++++ crates/deps-generator/src/types/mod.rs | 3 + packages/assets/deps/backend-deps.json | 10 +++ packages/assets/deps/frontend-deps.json | 14 ++++ .../components/settings/SettingsSidebar.tsx | 5 ++ .../interface/src/screens/settings/index.tsx | 1 + .../screens/settings/info/Dependencies.tsx | 47 ++++++++++++ 12 files changed, 286 insertions(+), 4 deletions(-) create mode 100644 crates/deps-generator/Cargo.toml create mode 100644 crates/deps-generator/src/main.rs create mode 100644 crates/deps-generator/src/types/backend.rs create mode 100644 crates/deps-generator/src/types/cli.rs create mode 100644 crates/deps-generator/src/types/frontend.rs create mode 100644 crates/deps-generator/src/types/mod.rs create mode 100644 packages/assets/deps/backend-deps.json create mode 100644 packages/assets/deps/frontend-deps.json create mode 100644 packages/interface/src/screens/settings/info/Dependencies.tsx diff --git a/Cargo.lock b/Cargo.lock index 86ec24ab2..4260b405b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -451,6 +451,12 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + [[package]] name = "base64ct" version = "1.5.2" @@ -732,6 +738,20 @@ dependencies = [ "serde_json", ] +[[package]] +name = "cargo_metadata" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.14", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cargo_toml" version = "0.11.8" @@ -1453,6 +1473,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "deps-generator" +version = "0.0.0" +dependencies = [ + "anyhow", + "cargo_metadata 0.15.3", + "clap", + "reqwest", + "serde", + "serde_json", +] + [[package]] name = "derivative" version = "2.2.0" @@ -5219,11 +5251,11 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.12" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc" +checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" dependencies = [ - "base64 0.13.1", + "base64 0.21.0", "bytes", "encoding_rs", "futures-core", @@ -6104,7 +6136,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" dependencies = [ "bytecount", - "cargo_metadata", + "cargo_metadata 0.14.2", "error-chain", "glob", "pulldown-cmark", diff --git a/crates/deps-generator/Cargo.toml b/crates/deps-generator/Cargo.toml new file mode 100644 index 000000000..cd3864d7c --- /dev/null +++ b/crates/deps-generator/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "deps-generator" +version = "0.0.0" +edition = "2021" +authors = ["Jake Robinson "] +description = "A tool to compile all Spacedrive dependencies and their respective licenses" + +[dependencies] +reqwest = { version = "0.11.14", features = ["blocking"] } +clap = { version = "4.0.32", features = ["derive"] } +anyhow = "1.0.68" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +cargo_metadata = "0.15.3" diff --git a/crates/deps-generator/src/main.rs b/crates/deps-generator/src/main.rs new file mode 100644 index 000000000..42c81ec84 --- /dev/null +++ b/crates/deps-generator/src/main.rs @@ -0,0 +1,75 @@ +use anyhow::Result; +use cargo_metadata::CargoOpt; +use clap::Parser; +use std::{fs::File, path::PathBuf}; +use types::{ + backend::BackendDependency, + cli::{Action, Arguments}, + frontend::FrontendDependency, +}; + +pub mod types; + +const FOSSA_BASE_URL: &str = + "https://app.fossa.com/api/revisions/git%2Bgithub.com%2Fspacedriveapp%2Fspacedrive%24"; + +fn main() -> Result<()> { + let args = Arguments::parse(); + + match args.action { + Action::Frontend(sub_args) => write_frontend_deps(sub_args.revision, sub_args.path), + Action::Backend(sub_args) => { + write_backend_deps(sub_args.manifest_path, sub_args.output_path) + } + } +} + +fn write_backend_deps(manifest_path: PathBuf, output_path: PathBuf) -> Result<()> { + let cmd = cargo_metadata::MetadataCommand::new() + .manifest_path(manifest_path) + .features(CargoOpt::AllFeatures) + .exec()?; + + let deps: Vec = cmd + .packages + .into_iter() + .filter_map(|p| { + (!cmd.workspace_members.iter().any(|t| &p.id == t)).then_some(BackendDependency { + title: p.name, + description: p.description, + url: p.repository, + version: p.version.to_string(), + authors: p.authors, + license: p.license, + }) + }) + .collect(); + + let mut file = File::create(output_path)?; + serde_json::to_writer(&mut file, &deps)?; + + Ok(()) +} + +fn write_frontend_deps(rev: String, path: PathBuf) -> Result<()> { + let url = format!("{FOSSA_BASE_URL}{rev}/dependencies"); + + let response = reqwest::blocking::get(url)?.text()?; + let json: Vec = serde_json::from_str(&response)?; + + let deps: Vec<_> = json + .into_iter() + .map(|dep| FrontendDependency { + title: dep.project.title, + authors: dep.project.authors, + description: dep.project.description, + url: dep.project.url, + license: dep.licenses, + }) + .collect(); + + let mut file = File::create(path)?; + serde_json::to_writer(&mut file, &deps)?; + + Ok(()) +} diff --git a/crates/deps-generator/src/types/backend.rs b/crates/deps-generator/src/types/backend.rs new file mode 100644 index 000000000..c78440e5d --- /dev/null +++ b/crates/deps-generator/src/types/backend.rs @@ -0,0 +1,12 @@ +use serde::Serialize; + +#[allow(clippy::module_name_repetitions)] +#[derive(Serialize)] +pub struct BackendDependency { + pub title: String, + pub description: Option, + pub url: Option, + pub version: String, + pub authors: Vec, + pub license: Option, +} diff --git a/crates/deps-generator/src/types/cli.rs b/crates/deps-generator/src/types/cli.rs new file mode 100644 index 000000000..0ad792921 --- /dev/null +++ b/crates/deps-generator/src/types/cli.rs @@ -0,0 +1,33 @@ +use std::path::PathBuf; + +use clap::{Args, Parser, Subcommand}; + +#[derive(Parser)] +pub struct Arguments { + #[command(subcommand)] + pub action: Action, +} + +#[derive(Subcommand)] +pub enum Action { + Frontend(FrontendArgs), + Backend(BackendArgs), +} + +#[derive(Args)] +pub struct FrontendArgs { + // could source this from `$GITHUB_SHA` for CI, if not set + #[arg(help = "the git revision")] + pub revision: String, + #[arg(help = "the output path")] + pub path: PathBuf, +} + +#[derive(Args)] +pub struct BackendArgs { + // could use `Cargo.toml` as the default from current dir (if not set) + #[arg(help = "path to the cargo manifest")] + pub manifest_path: PathBuf, + #[arg(help = "the output path")] + pub output_path: PathBuf, +} diff --git a/crates/deps-generator/src/types/frontend.rs b/crates/deps-generator/src/types/frontend.rs new file mode 100644 index 000000000..dcc0b3e02 --- /dev/null +++ b/crates/deps-generator/src/types/frontend.rs @@ -0,0 +1,36 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct Dependency { + pub project: Project, + pub licenses: Vec, +} + +#[derive(Serialize, Deserialize)] +pub struct Project { + // pub locator: Option, + pub title: String, + pub description: Option, + pub url: Option, + pub authors: Vec>, +} + +#[derive(Serialize, Deserialize)] +pub struct License { + pub text: Option, + // pub license_id: Option, // always null AFAIK + pub copyright: Option, + // pub license_group_id: i64, + // pub ignored: bool, // always false from my testing + // pub revision_id: Option, +} + +#[allow(clippy::module_name_repetitions)] +#[derive(Serialize)] +pub struct FrontendDependency { + pub title: String, + pub description: Option, + pub url: Option, + pub authors: Vec>, + pub license: Vec, +} diff --git a/crates/deps-generator/src/types/mod.rs b/crates/deps-generator/src/types/mod.rs new file mode 100644 index 000000000..8e51afb58 --- /dev/null +++ b/crates/deps-generator/src/types/mod.rs @@ -0,0 +1,3 @@ +pub mod backend; +pub mod cli; +pub mod frontend; diff --git a/packages/assets/deps/backend-deps.json b/packages/assets/deps/backend-deps.json new file mode 100644 index 000000000..9cfa2263a --- /dev/null +++ b/packages/assets/deps/backend-deps.json @@ -0,0 +1,10 @@ +[ + { + "title": "Placeholder", + "description": "", + "url": "https://spacedrive.com", + "version": "0.0.0", + "authors": [""], + "license": "" + } +] diff --git a/packages/assets/deps/frontend-deps.json b/packages/assets/deps/frontend-deps.json new file mode 100644 index 000000000..9b50fe4c9 --- /dev/null +++ b/packages/assets/deps/frontend-deps.json @@ -0,0 +1,14 @@ +[ + { + "title": "Placeholder", + "description": "", + "url": "https://spacedrive.com", + "authors": [""], + "license": [ + { + "text": "", + "copyright": "" + } + ] + } +] diff --git a/packages/interface/src/components/settings/SettingsSidebar.tsx b/packages/interface/src/components/settings/SettingsSidebar.tsx index 929574dae..bd11f4e1c 100644 --- a/packages/interface/src/components/settings/SettingsSidebar.tsx +++ b/packages/interface/src/components/settings/SettingsSidebar.tsx @@ -2,6 +2,7 @@ import { Books, FlyingSaucer, GearSix, + Graph, HardDrive, Heart, Key, @@ -83,6 +84,10 @@ export const SettingsSidebar = () => { Changelog + + + Dependencies + Support diff --git a/packages/interface/src/screens/settings/index.tsx b/packages/interface/src/screens/settings/index.tsx index f4705e24d..968abb5ab 100644 --- a/packages/interface/src/screens/settings/index.tsx +++ b/packages/interface/src/screens/settings/index.tsx @@ -26,6 +26,7 @@ const routes: RouteProps[] = [ { path: 'privacy', element: lazyEl(() => import('./client/PrivacySettings')) }, { path: 'about', element: lazyEl(() => import('./info/AboutSpacedrive')) }, { path: 'changelog', element: lazyEl(() => import('./info/Changelog')) }, + { path: 'dependencies', element: lazyEl(() => import('./info/Dependencies')) }, { path: 'support', element: lazyEl(() => import('./info/Support')) } ]; diff --git a/packages/interface/src/screens/settings/info/Dependencies.tsx b/packages/interface/src/screens/settings/info/Dependencies.tsx new file mode 100644 index 000000000..354b0b7d0 --- /dev/null +++ b/packages/interface/src/screens/settings/info/Dependencies.tsx @@ -0,0 +1,47 @@ +import { useQuery } from '@tanstack/react-query'; +import { ScreenHeading } from '@sd/ui'; +import { usePlatform } from '~/util/Platform'; + +export default function DependenciesScreen() { + const frontEnd = useQuery(['frontend-deps'], () => import('@sd/assets/deps/frontend-deps.json')); + const backEnd = useQuery(['backend-deps'], () => import('@sd/assets/deps/backend-deps.json')); + const platform = usePlatform(); + + return ( +
+ Dependencies + + {/* item has a LOT more data that we can display, i just went with the basics */} + + Frontend Dependencies +
+ {frontEnd.data && + frontEnd.data?.default.map((item) => { + return ( + platform.openLink(item.url ?? '')}> +
+

+ {item.title.trimEnd().substring(0, 24) + (item.title.length > 24 ? '...' : '')} +

+
+
+ ); + })} +
+ + Backend Dependencies +
+ {backEnd.data && + backEnd.data?.default.map((item) => { + return ( + platform.openLink(item.url ?? '')}> +
+

{item.title.trimEnd()}

+
+
+ ); + })} +
+
+ ); +}