1+ use std:: collections:: HashSet ;
2+
13use cargo:: core:: registry:: PackageRegistry ;
24use cargo:: core:: QueryKind ;
35use cargo:: core:: Registry ;
46use cargo:: core:: SourceId ;
7+ use cargo:: ops:: Packages ;
58use cargo:: util:: command_prelude:: * ;
69
710pub fn cli ( ) -> clap:: Command {
811 clap:: Command :: new ( "xtask-unpublished" )
12+ . arg_package_spec_simple ( "Package to inspect the published status" )
913 . arg (
1014 opt (
1115 "verbose" ,
@@ -76,14 +80,24 @@ fn config_configure(config: &mut Config, args: &ArgMatches) -> CliResult {
7680
7781fn unpublished ( args : & clap:: ArgMatches , config : & mut cargo:: util:: Config ) -> cargo:: CliResult {
7882 let ws = args. workspace ( config) ?;
83+
84+ let members_to_inspect: HashSet < _ > = {
85+ let pkgs = args. packages_from_flags ( ) ?;
86+ if let Packages :: Packages ( _) = pkgs {
87+ HashSet :: from_iter ( pkgs. get_packages ( & ws) ?)
88+ } else {
89+ HashSet :: from_iter ( ws. members ( ) )
90+ }
91+ } ;
92+
7993 let mut results = Vec :: new ( ) ;
8094 {
8195 let mut registry = PackageRegistry :: new ( config) ?;
8296 let _lock = config. acquire_package_cache_lock ( ) ?;
8397 registry. lock_patches ( ) ;
8498 let source_id = SourceId :: crates_io ( config) ?;
8599
86- for member in ws . members ( ) {
100+ for member in members_to_inspect {
87101 let name = member. name ( ) ;
88102 let current = member. version ( ) ;
89103 if member. publish ( ) == & Some ( vec ! [ ] ) {
@@ -92,11 +106,8 @@ fn unpublished(args: &clap::ArgMatches, config: &mut cargo::util::Config) -> car
92106 }
93107
94108 let version_req = format ! ( "<={current}" ) ;
95- let query = cargo:: core:: dependency:: Dependency :: parse (
96- name,
97- Some ( & version_req) ,
98- source_id. clone ( ) ,
99- ) ?;
109+ let query =
110+ cargo:: core:: dependency:: Dependency :: parse ( name, Some ( & version_req) , source_id) ?;
100111 let possibilities = loop {
101112 // Exact to avoid returning all for path/git
102113 match registry. query_vec ( & query, QueryKind :: Exact ) {
@@ -106,51 +117,77 @@ fn unpublished(args: &clap::ArgMatches, config: &mut cargo::util::Config) -> car
106117 std:: task:: Poll :: Pending => registry. block_until_ready ( ) ?,
107118 }
108119 } ;
109- if let Some ( last) = possibilities. iter ( ) . map ( |s| s . version ( ) ) . max ( ) {
110- if last != current {
111- results . push ( (
112- name . to_string ( ) ,
113- Some ( last. to_string ( ) ) ,
114- current . to_string ( ) ,
115- ) ) ;
116- } else {
117- log :: trace! ( "{ name} {current} is published" ) ;
118- }
119- } else {
120- results . push ( ( name . to_string ( ) , None , current . to_string ( ) ) ) ;
121- }
120+ let ( last, published ) = possibilities
121+ . iter ( )
122+ . map ( |s| s . version ( ) )
123+ . max ( )
124+ . map ( |last| ( last. to_string ( ) , last == current ) )
125+ . unwrap_or ( ( "-" . to_string ( ) , false ) ) ;
126+
127+ results . push ( vec ! [
128+ name. to_string ( ) ,
129+ last ,
130+ current . to_string ( ) ,
131+ if published { "yes" } else { "no" } . to_string( ) ,
132+ ] ) ;
122133 }
123134 }
135+ results. sort ( ) ;
124136
125- if !results. is_empty ( ) {
126- results. insert (
127- 0 ,
128- (
129- "name" . to_owned ( ) ,
130- Some ( "published" . to_owned ( ) ) ,
131- "current" . to_owned ( ) ,
132- ) ,
133- ) ;
134- results. insert (
135- 1 ,
136- (
137- "====" . to_owned ( ) ,
138- Some ( "=========" . to_owned ( ) ) ,
139- "=======" . to_owned ( ) ,
140- ) ,
141- ) ;
142- }
143- for ( name, last, current) in results {
144- if let Some ( last) = last {
145- println ! ( "{name} {last} {current}" ) ;
146- } else {
147- println ! ( "{name} - {current}" ) ;
148- }
137+ if results. is_empty ( ) {
138+ return Ok ( ( ) ) ;
149139 }
150140
141+ results. insert (
142+ 0 ,
143+ vec ! [
144+ "name" . to_owned( ) ,
145+ "crates.io" . to_owned( ) ,
146+ "local" . to_owned( ) ,
147+ "published?" . to_owned( ) ,
148+ ] ,
149+ ) ;
150+
151+ output_table ( results) ;
152+
151153 Ok ( ( ) )
152154}
153155
156+ /// Outputs a markdown table like this.
157+ ///
158+ /// ```text
159+ /// | name | crates.io | local | published? |
160+ /// |------------------|-----------|--------|------------|
161+ /// | cargo | 0.70.1 | 0.72.0 | no |
162+ /// | cargo-platform | 0.1.2 | 0.1.2 | yes |
163+ /// | cargo-util | - | 0.2.4 | no |
164+ /// | crates-io | 0.36.0 | 0.36.0 | yes |
165+ /// | home | - | 0.5.6 | no |
166+ /// ```
167+ fn output_table ( table : Vec < Vec < String > > ) {
168+ let header = table. first ( ) . unwrap ( ) ;
169+ let paddings = table. iter ( ) . fold ( vec ! [ 0 ; header. len( ) ] , |mut widths, row| {
170+ for ( width, field) in widths. iter_mut ( ) . zip ( row) {
171+ * width = usize:: max ( * width, field. len ( ) ) ;
172+ }
173+ widths
174+ } ) ;
175+
176+ let print = |row : & [ _ ] | {
177+ for ( field, pad) in row. iter ( ) . zip ( & paddings) {
178+ print ! ( "| {field:pad$} " ) ;
179+ }
180+ println ! ( "|" ) ;
181+ } ;
182+
183+ print ( header) ;
184+
185+ paddings. iter ( ) . for_each ( |fill| print ! ( "|-{:-<fill$}-" , "" ) ) ;
186+ println ! ( "|" ) ;
187+
188+ table. iter ( ) . skip ( 1 ) . for_each ( |r| print ( r) ) ;
189+ }
190+
154191#[ test]
155192fn verify_cli ( ) {
156193 cli ( ) . debug_assert ( ) ;
0 commit comments