Skip to content

Commit 1087361

Browse files
committed
Add menu item called Feature flags
Feature flags should show all available features for current crate version with default being first is specified.
1 parent 27dcd99 commit 1087361

File tree

8 files changed

+110
-8
lines changed

8 files changed

+110
-8
lines changed

Cargo.lock

+19-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ lol_html = "0.2"
5353
font-awesome-as-a-crate = { path = "crates/font-awesome-as-a-crate" }
5454
dashmap = "3.11.10"
5555
string_cache = "0.8.0"
56+
postgres-types = { version = "0.1.3", features = ["derive"] }
5657

5758
# Async
5859
tokio = { version = "0.2.22", features = ["rt-threaded"] }

src/db/add_package.rs

+31-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::{
55
};
66

77
use crate::{
8+
db::types::Feature,
89
docbuilder::{BuildResult, DocCoverage},
910
error::Result,
1011
index::api::{CrateData, CrateOwner, ReleaseData},
@@ -42,6 +43,7 @@ pub(crate) fn add_package_into_database(
4243
let dependencies = convert_dependencies(metadata_pkg);
4344
let rustdoc = get_rustdoc(metadata_pkg, source_dir).unwrap_or(None);
4445
let readme = get_readme(metadata_pkg, source_dir).unwrap_or(None);
46+
let features = get_features(metadata_pkg);
4547
let is_library = metadata_pkg.is_library();
4648

4749
let rows = conn.query(
@@ -52,12 +54,12 @@ pub(crate) fn add_package_into_database(
5254
homepage_url, description, description_long, readme,
5355
authors, keywords, have_examples, downloads, files,
5456
doc_targets, is_library, doc_rustc_version,
55-
documentation_url, default_target
57+
documentation_url, default_target, features
5658
)
5759
VALUES (
5860
$1, $2, $3, $4, $5, $6, $7, $8, $9,
5961
$10, $11, $12, $13, $14, $15, $16, $17, $18,
60-
$19, $20, $21, $22, $23, $24, $25
62+
$19, $20, $21, $22, $23, $24, $25, $26
6163
)
6264
ON CONFLICT (crate_id, version) DO UPDATE
6365
SET release_time = $3,
@@ -82,7 +84,8 @@ pub(crate) fn add_package_into_database(
8284
is_library = $22,
8385
doc_rustc_version = $23,
8486
documentation_url = $24,
85-
default_target = $25
87+
default_target = $25,
88+
features = $26
8689
RETURNING id",
8790
&[
8891
&crate_id,
@@ -110,6 +113,7 @@ pub(crate) fn add_package_into_database(
110113
&res.rustc_version,
111114
&metadata_pkg.documentation,
112115
&default_target,
116+
&features,
113117
],
114118
)?;
115119

@@ -213,6 +217,30 @@ fn convert_dependencies(pkg: &MetadataPackage) -> Vec<(String, String, String)>
213217
.collect()
214218
}
215219

220+
/// Reads features and converts them to Vec<Feature> with default being first
221+
fn get_features(pkg: &MetadataPackage) -> Vec<Feature> {
222+
let mut features = Vec::with_capacity(pkg.features.len());
223+
if let Some(subfeatures) = pkg.features.get("default") {
224+
features.push(Feature::new("default".into(), subfeatures.clone()));
225+
};
226+
features.extend(
227+
pkg.features
228+
.iter()
229+
.filter(|(name, _)| name != "default")
230+
.map(|(name, subfeatures)| Feature::new(name.clone(), subfeatures.clone())),
231+
);
232+
features.extend(get_optional_features(pkg));
233+
features
234+
}
235+
236+
fn get_optional_features(pkg: &MetadataPackage) -> Vec<Feature> {
237+
pkg.dependencies
238+
.iter()
239+
.filter(|dep| dep.optional)
240+
.map(|dep| Feature::new(dep.name.clone(), Vec::new()))
241+
.collect()
242+
}
243+
216244
/// Reads readme if there is any read defined in Cargo.toml of a Package
217245
fn get_readme(pkg: &MetadataPackage, source_dir: &Path) -> Result<Option<String>> {
218246
let readme_path = source_dir.join(pkg.readme.as_deref().unwrap_or("README.md"));

src/db/migrate.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,24 @@ pub fn migrate(version: Option<Version>, conn: &mut Client) -> CratesfyiResult<(
457457
DROP COLUMN total_items_needing_examples,
458458
DROP COLUMN items_with_examples;
459459
"
460-
)
460+
),
461+
migration!(
462+
context,
463+
// version
464+
19,
465+
// description
466+
"Add features that are available for given release",
467+
// upgrade query
468+
"
469+
CREATE TYPE feature AS (name TEXT, subfeatures TEXT[]);
470+
ALTER TABLE releases ADD COLUMN features feature[];
471+
",
472+
// downgrade query
473+
"
474+
ALTER TABLE releases DROP COLUMN features;
475+
DROP TYPE feature;
476+
"
477+
),
461478
];
462479

463480
for migration in migrations {

src/db/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ mod delete;
1515
pub(crate) mod file;
1616
mod migrate;
1717
mod pool;
18+
pub(crate) mod types;

src/db/types.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use failure::_core::fmt::Formatter;
2+
use postgres_types::{FromSql, ToSql};
3+
use serde::Serialize;
4+
5+
#[derive(Debug, Clone, PartialEq, Serialize, FromSql, ToSql)]
6+
#[postgres(name = "feature")]
7+
pub struct Feature {
8+
name: String,
9+
subfeatures: Vec<String>,
10+
}
11+
12+
impl Feature {
13+
pub fn new(name: String, subfeatures: Vec<String>) -> Self {
14+
Feature { name, subfeatures }
15+
}
16+
17+
pub fn is_private(&self) -> bool {
18+
self.name.starts_with('_')
19+
}
20+
}
21+
22+
impl std::fmt::Display for Feature {
23+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
24+
write!(f, "{} = {:?}", self.name, self.subfeatures)
25+
}
26+
}

src/test/fakes.rs

+12
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use crate::storage::Storage;
55
use crate::utils::{Dependency, MetadataPackage, Target};
66
use chrono::{DateTime, Utc};
77
use failure::Error;
8+
use futures_util::TryStreamExt;
9+
use std::collections::HashMap;
810
use std::sync::Arc;
911

1012
#[must_use = "FakeRelease does nothing until you call .create()"]
@@ -48,11 +50,21 @@ impl<'a> FakeRelease<'a> {
4850
name: "fake-dependency".into(),
4951
req: "^1.0.0".into(),
5052
kind: None,
53+
optional: false,
5154
}],
5255
targets: vec![Target::dummy_lib("fake_package".into(), None)],
5356
readme: None,
5457
keywords: vec!["fake".into(), "package".into()],
5558
authors: vec!["Fake Person <[email protected]>".into()],
59+
features: [
60+
("default".into(), vec!["feature1".into(), "feature3".into()]),
61+
("feature1".into(), Vec::new()),
62+
("feature2".into(), vec!["feature1".into()]),
63+
("feature3".into(), Vec::new()),
64+
]
65+
.iter()
66+
.cloned()
67+
.collect::<HashMap<String, Vec<String>>>(),
5668
},
5769
build_result: BuildResult {
5870
rustc_version: "rustc 2.0.0-nightly (000000000 1970-01-01)".into(),

src/utils/cargo_metadata.rs

+2
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ pub(crate) struct Package {
7777
pub(crate) readme: Option<String>,
7878
pub(crate) keywords: Vec<String>,
7979
pub(crate) authors: Vec<String>,
80+
pub(crate) features: HashMap<String, Vec<String>>,
8081
}
8182

8283
impl Package {
@@ -131,6 +132,7 @@ pub(crate) struct Dependency {
131132
pub(crate) name: String,
132133
pub(crate) req: String,
133134
pub(crate) kind: Option<String>,
135+
pub(crate) optional: bool,
134136
}
135137

136138
#[derive(Deserialize, Serialize)]

0 commit comments

Comments
 (0)