Skip to content

Commit 98d52d3

Browse files
authored
Merge pull request #5 from shanselman/copilot/implement-handling-of-pins
Fix winget pin message parsing in upgrade table output
2 parents 6ffd22b + cb94640 commit 98d52d3

File tree

1 file changed

+74
-4
lines changed

1 file changed

+74
-4
lines changed

src/cli_backend.rs

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,12 @@ impl CliBackend {
7474
lines[sep_idx + 1..]
7575
.iter()
7676
.filter(|l| !l.trim().is_empty())
77-
// Stop at footer lines like "123 upgrades available."
78-
// These are short lines with a digit followed by a word — distinct from data rows
79-
// which span the full table width
80-
.take_while(|l| l.len() > 20 || !l.trim_start().starts_with(|c: char| c.is_ascii_digit()))
77+
// Stop at footer lines that start with a digit, such as:
78+
// - "2 upgrades available."
79+
// - "2 packages have pins that prevent upgrade..."
80+
// - "2 Pakete verfügen über Pins, die ein Upgrade verhindern..."
81+
// These lines indicate end of table data and start of informational messages.
82+
.take_while(|l| !l.trim_start().starts_with(|c: char| c.is_ascii_digit()))
8183
.filter_map(|line| self.parse_table_row(line, &col_positions))
8284
.collect()
8385
}
@@ -523,4 +525,72 @@ Google Chrome Google.Chrome 131.0.6 winget
523525
assert_eq!(packages[0].source, "winget");
524526
assert!(packages[0].available_version.is_empty());
525527
}
528+
529+
#[test]
530+
fn parse_upgrade_table_with_german_pin_message() {
531+
let backend = CliBackend::new();
532+
// Real output from winget upgrade with pinned packages (German locale)
533+
let output = "\
534+
Name ID Version Verfügbar Quelle
535+
-------------------------------------------------------------------------------------------------
536+
RamMap Microsoft.Sysinternals.R... 1.61 1.62 winget
537+
vc_clip vc_clip.vc_dir 2026.01.29 winget
538+
2 Pakete verfügen über Pins, die ein Upgrade verhindern. Verwenden Sie den Befehl \"winget pin\", um Pins anzuzeigen und zu bearbeiten. Wenn Sie das --include-pinned-Argument verwenden, werden möglicherweise weitere Ergebnisse angezeigt.
539+
";
540+
let packages = backend.parse_packages_from_table(output);
541+
assert_eq!(packages.len(), 2, "should parse only the package rows, not the pin message");
542+
assert_eq!(packages[0].id, "Microsoft.Sysinternals.R...");
543+
assert_eq!(packages[0].version, "1.61");
544+
assert_eq!(packages[0].available_version, "1.62");
545+
assert_eq!(packages[1].id, "vc_clip.vc_dir");
546+
}
547+
548+
#[test]
549+
fn parse_upgrade_table_with_english_pin_message() {
550+
let backend = CliBackend::new();
551+
// English version of pin message
552+
let output = "\
553+
Name Id Version Available Source
554+
-------------------------------------------------------------------------------------------------
555+
Google Chrome Google.Chrome 131.0.6778 132.0.6834 winget
556+
2 packages have pins that prevent upgrade. Use the \"winget pin\" command to view and edit pins. If you use the --include-pinned argument, additional results may be displayed.
557+
";
558+
let packages = backend.parse_packages_from_table(output);
559+
assert_eq!(packages.len(), 1, "should parse only the package rows, not the pin message");
560+
assert_eq!(packages[0].id, "Google.Chrome");
561+
assert_eq!(packages[0].available_version, "132.0.6834");
562+
}
563+
564+
#[test]
565+
fn parse_upgrade_table_with_upgrades_available_footer() {
566+
let backend = CliBackend::new();
567+
// Footer message indicating number of upgrades
568+
let output = "\
569+
Name Id Version Available Source
570+
-------------------------------------------------------------------------------------------------
571+
Google Chrome Google.Chrome 131.0.6778 132.0.6834 winget
572+
Microsoft Visual Studio Code Microsoft.VisualStudioCode 1.95.3 1.96.0 winget
573+
2 upgrades available.
574+
";
575+
let packages = backend.parse_packages_from_table(output);
576+
assert_eq!(packages.len(), 2, "should parse package rows, stopping at footer");
577+
assert_eq!(packages[0].id, "Google.Chrome");
578+
assert_eq!(packages[1].id, "Microsoft.VisualStudioCode");
579+
}
580+
581+
#[test]
582+
fn parse_upgrade_table_with_multiple_footer_lines() {
583+
let backend = CliBackend::new();
584+
// Multiple footer messages
585+
let output = "\
586+
Name Id Version Available Source
587+
-------------------------------------------------------------------------------------------------
588+
Google Chrome Google.Chrome 131.0.6778 132.0.6834 winget
589+
1 upgrade available.
590+
2 packages have pins that prevent upgrade. Use the \"winget pin\" command to view and edit pins.
591+
";
592+
let packages = backend.parse_packages_from_table(output);
593+
assert_eq!(packages.len(), 1, "should stop at first footer line");
594+
assert_eq!(packages[0].id, "Google.Chrome");
595+
}
526596
}

0 commit comments

Comments
 (0)