-
Notifications
You must be signed in to change notification settings - Fork 68
Expand file tree
/
Copy pathdata.rs
More file actions
128 lines (112 loc) · 3.92 KB
/
data.rs
File metadata and controls
128 lines (112 loc) · 3.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use crate::github::RepoData;
use chrono::{DateTime, Utc};
use crates_io_api::Crate;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub enum Topic {
ScientificComputing,
GpuComputing,
NeuralNetworks,
Metaheuristics,
Mlops,
DataPreprocessing,
DataStructures,
Clustering,
DecisionTrees,
LinearClassifiers,
Reinforcement,
Nlp,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct InputCrateInfo {
pub name: Option<String>,
pub topics: Vec<Topic>,
//overridable crate fields
pub documentation: Option<String>,
pub repository: Option<Url>,
pub license: Option<String>,
pub description: Option<String>,
}
#[derive(Serialize, Clone, Debug)]
pub struct GeneratedCrateInfo {
pub topics: Vec<Topic>,
pub score: Option<u64>,
#[serde(rename = "meta", skip_serializing_if = "Option::is_none")]
pub krate: Option<Crate>,
#[serde(rename = "repo", skip_serializing_if = "Option::is_none")]
pub repo: Option<RepoData>,
}
impl From<&InputCrateInfo> for GeneratedCrateInfo {
fn from(input: &InputCrateInfo) -> Self {
GeneratedCrateInfo {
topics: input.topics.clone(),
score: None,
krate: None,
repo: None,
}
}
}
// New value takes precedent if it exists
fn replace_opt<T: Clone>(original: &mut Option<T>, extra: &Option<T>) {
if let Some(val) = extra {
let _ = original.replace(val.clone());
}
}
// Helper to allow specific fields from crates.yml
// to override the values returned by the Crates.io API
pub fn override_crate_data(krate: &mut Crate, input: &InputCrateInfo) {
replace_opt(&mut krate.license, &input.license);
replace_opt(&mut krate.documentation, &input.documentation);
if krate.documentation.is_none() {
krate.documentation = Some(format!("https://docs.rs/crate/{}", krate.name));
}
replace_opt(
&mut krate.repository,
&input.repository.as_ref().map(|r| r.to_string()),
);
replace_opt(&mut krate.description, &input.description);
}
impl GeneratedCrateInfo {
// In calculating last_activity, we only scrape last_commit for github-based crates
// so this is unfair to projects that host source elsewhere.
// This is slightly mitigated by falling back to the last crate publish date
fn last_activity(&self) -> Option<DateTime<Utc>> {
let mut last_activity = self.krate.as_ref().map(|k| k.updated_at);
if let Some(last_commit) = self.repo.as_ref().map(|r| r.last_commit) {
if Some(last_commit) > last_activity {
last_activity = Some(last_commit);
}
}
last_activity
}
pub fn update_score(&mut self) {
if self.krate.is_none() {
// crate is not published to crates.io
self.score = Some(0);
}
let coefficient = match self.last_activity() {
None => 0.1,
Some(last_activity) => {
let inactive_days = (Utc::now() - last_activity).num_days();
// This is really simple, but basically calls any crate with activity in 6 months as maintained
// trying to recognize that some crates may actually be stable enough to require infrequent changes
// From 6-12 months, it's maintenance state is less certain, and after a year without activity, it's likely unmaintained
if inactive_days <= 180 {
1.0
} else if inactive_days <= 365 {
0.5
} else {
0.1
}
}
};
let recent_downloads = self
.krate
.as_ref()
.and_then(|k| k.recent_downloads)
.unwrap_or(0);
self.score = Some(f32::floor(coefficient * recent_downloads as f32) as u64);
}
}