1- use crate :: schema:: { crate_owners , teams , users } ;
1+ use crate :: schema:: crate_downloads ;
22use crate :: worker:: jobs;
33use crate :: { admin:: dialoguer, db, schema:: crates} ;
44use anyhow:: Context ;
5+ use colored:: Colorize ;
56use crates_io_worker:: BackgroundJob ;
67use diesel:: dsl:: sql;
7- use diesel:: sql_types:: Text ;
8- use diesel:: { ExpressionMethods , JoinOnDsl , QueryDsl } ;
8+ use diesel:: sql_types:: { Array , BigInt , Text } ;
9+ use diesel:: { ExpressionMethods , QueryDsl } ;
910use diesel_async:: RunQueryDsl ;
11+ use futures_util:: TryStreamExt ;
1012use std:: collections:: HashMap ;
13+ use std:: fmt:: Display ;
1114
1215#[ derive( clap:: Parser , Debug ) ]
1316#[ command(
@@ -33,39 +36,60 @@ pub async fn run(opts: Opts) -> anyhow::Result<()> {
3336 let mut crate_names = opts. crate_names ;
3437 crate_names. sort ( ) ;
3538
36- let query_result = crates:: table
39+ let existing_crates = crates:: table
40+ . inner_join ( crate_downloads:: table)
41+ . filter ( crates:: name. eq_any ( & crate_names) )
3742 . select ( (
3843 crates:: name,
3944 crates:: id,
40- sql :: < Text > (
41- "CASE WHEN crate_owners.owner_kind = 1 THEN teams.login ELSE users.gh_login END" ,
45+ crate_downloads:: downloads,
46+ sql :: < Array < Text > > (
47+ r#"
48+ ARRAY(
49+ SELECT
50+ CASE WHEN crate_owners.owner_kind = 1 THEN
51+ teams.login
52+ ELSE
53+ users.gh_login
54+ END
55+ FROM crate_owners
56+ LEFT JOIN teams ON teams.id = crate_owners.owner_id
57+ LEFT JOIN users ON users.id = crate_owners.owner_id
58+ WHERE crate_owners.crate_id = crates.id
59+ )
60+ "# ,
61+ ) ,
62+ sql :: < BigInt > (
63+ // This is an incorrect reverse dependencies query, since it
64+ // includes the `dependencies` rows for all versions, not just
65+ // the "default version" per crate. However, it's good enough
66+ // for our purposes here.
67+ r#"
68+ (
69+ SELECT COUNT(*)
70+ FROM dependencies
71+ WHERE dependencies.crate_id = crates.id
72+ )
73+ "# ,
4274 ) ,
4375 ) )
44- . left_join ( crate_owners:: table. on ( crate_owners:: crate_id. eq ( crates:: id) ) )
45- . left_join ( teams:: table. on ( teams:: id. eq ( crate_owners:: owner_id) ) )
46- . left_join ( users:: table. on ( users:: id. eq ( crate_owners:: owner_id) ) )
47- . filter ( crates:: name. eq_any ( & crate_names) )
48- . load :: < ( String , i32 , String ) > ( & mut conn)
76+ . load_stream :: < ( String , i32 , i64 , Vec < String > , i64 ) > ( & mut conn)
4977 . await
50- . context ( "Failed to look up crate name from the database" ) ?;
51-
52- let mut existing_crates: HashMap < String , ( i32 , Vec < String > ) > = HashMap :: new ( ) ;
53- for ( name, id, login) in query_result {
54- let entry = existing_crates
55- . entry ( name)
56- . or_insert_with ( || ( id, Vec :: new ( ) ) ) ;
57-
58- entry. 1 . push ( login) ;
59- }
78+ . context ( "Failed to look up crate name from the database" ) ?
79+ . try_fold (
80+ HashMap :: new ( ) ,
81+ |mut map, ( name, id, downloads, owners, rev_deps) | {
82+ map. insert ( name, CrateInfo :: new ( id, downloads, owners, rev_deps) ) ;
83+ futures_util:: future:: ready ( Ok ( map) )
84+ } ,
85+ )
86+ . await ?;
6087
6188 println ! ( "Deleting the following crates:" ) ;
6289 println ! ( ) ;
6390 for name in & crate_names {
6491 match existing_crates. get ( name) {
65- Some ( ( id, owners) ) => {
66- let owners = owners. join ( ", " ) ;
67- println ! ( " - {name} (id={id}, owners={owners})" ) ;
68- }
92+ Some ( info) => println ! ( " - {} ({info})" , name. bold( ) ) ,
6993 None => println ! ( " - {name} (⚠️ crate not found)" ) ,
7094 }
7195 }
@@ -78,7 +102,9 @@ pub async fn run(opts: Opts) -> anyhow::Result<()> {
78102 }
79103
80104 for name in & crate_names {
81- if let Some ( ( id, _) ) = existing_crates. get ( name) {
105+ if let Some ( crate_info) = existing_crates. get ( name) {
106+ let id = crate_info. id ;
107+
82108 info ! ( "{name}: Deleting crate from the database…" ) ;
83109 if let Err ( error) = diesel:: delete ( crates:: table. find ( id) )
84110 . execute ( & mut conn)
@@ -110,3 +136,41 @@ pub async fn run(opts: Opts) -> anyhow::Result<()> {
110136
111137 Ok ( ( ) )
112138}
139+
140+ #[ derive( Debug , Clone ) ]
141+ struct CrateInfo {
142+ id : i32 ,
143+ downloads : i64 ,
144+ owners : Vec < String > ,
145+ rev_deps : i64 ,
146+ }
147+
148+ impl CrateInfo {
149+ pub fn new ( id : i32 , downloads : i64 , owners : Vec < String > , rev_deps : i64 ) -> Self {
150+ Self {
151+ id,
152+ downloads,
153+ owners,
154+ rev_deps,
155+ }
156+ }
157+ }
158+
159+ impl Display for CrateInfo {
160+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
161+ let id = self . id ;
162+ let owners = self . owners . join ( ", " ) ;
163+
164+ write ! ( f, "id={id}, owners={owners}" ) ?;
165+ if self . downloads > 5000 {
166+ let downloads = format ! ( "downloads={}" , self . downloads) . bright_red ( ) . bold ( ) ;
167+ write ! ( f, ", {downloads}" ) ?;
168+ }
169+ if self . rev_deps > 0 {
170+ let rev_deps = format ! ( "rev_deps={}" , self . rev_deps) . bright_red ( ) . bold ( ) ;
171+ write ! ( f, ", {rev_deps}" ) ?;
172+ }
173+
174+ Ok ( ( ) )
175+ }
176+ }
0 commit comments