|
1 | 1 | use std::collections::HashSet;
|
| 2 | + |
2 | 3 | use cargo::core::registry::PackageRegistry;
|
3 | 4 | use cargo::core::QueryKind;
|
4 | 5 | use cargo::core::Registry;
|
@@ -116,51 +117,77 @@ fn unpublished(args: &clap::ArgMatches, config: &mut cargo::util::Config) -> car
|
116 | 117 | std::task::Poll::Pending => registry.block_until_ready()?,
|
117 | 118 | }
|
118 | 119 | };
|
119 |
| - if let Some(last) = possibilities.iter().map(|s| s.version()).max() { |
120 |
| - if last != current { |
121 |
| - results.push(( |
122 |
| - name.to_string(), |
123 |
| - Some(last.to_string()), |
124 |
| - current.to_string(), |
125 |
| - )); |
126 |
| - } else { |
127 |
| - log::trace!("{name} {current} is published"); |
128 |
| - } |
129 |
| - } else { |
130 |
| - results.push((name.to_string(), None, current.to_string())); |
131 |
| - } |
| 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 | + ]); |
132 | 133 | }
|
133 | 134 | }
|
| 135 | + results.sort(); |
134 | 136 |
|
135 |
| - if !results.is_empty() { |
136 |
| - results.insert( |
137 |
| - 0, |
138 |
| - ( |
139 |
| - "name".to_owned(), |
140 |
| - Some("published".to_owned()), |
141 |
| - "current".to_owned(), |
142 |
| - ), |
143 |
| - ); |
144 |
| - results.insert( |
145 |
| - 1, |
146 |
| - ( |
147 |
| - "====".to_owned(), |
148 |
| - Some("=========".to_owned()), |
149 |
| - "=======".to_owned(), |
150 |
| - ), |
151 |
| - ); |
152 |
| - } |
153 |
| - for (name, last, current) in results { |
154 |
| - if let Some(last) = last { |
155 |
| - println!("{name} {last} {current}"); |
156 |
| - } else { |
157 |
| - println!("{name} - {current}"); |
158 |
| - } |
| 137 | + if results.is_empty() { |
| 138 | + return Ok(()); |
159 | 139 | }
|
160 | 140 |
|
| 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 | + |
161 | 153 | Ok(())
|
162 | 154 | }
|
163 | 155 |
|
| 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.iter().next().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 | + |
164 | 191 | #[test]
|
165 | 192 | fn verify_cli() {
|
166 | 193 | cli().debug_assert();
|
|
0 commit comments