Match profiles list output liberally when sweeping profiles
macOS 26 lists profiles as attribute lines (profileIdentifier:) rather
than the key-value layout the parser assumed, so profile:remove found
nothing. Scan for the identifier anywhere in the output instead; the
real format is pinned as a test.
Assisted-by: GLM 5.2 via pi
diff --git a/lib/pro_tacts/profile.rb b/lib/pro_tacts/profile.rb
index 3ca188e..0c5664b 100644
--- a/lib/pro_tacts/profile.rb
+++ b/lib/pro_tacts/profile.rb
@@ -33,10 +33,11 @@ module ProTacts
# Picks our profile identifiers out of `profiles list` output so
# profile:remove can sweep every pro-tacts profile, not just the latest.
+ # Scans for the prefix anywhere in the output rather than assuming a
+ # key-value layout, since the listing format has changed across macOS
+ # versions (key-value today, table under later releases).
def self.installed_identifiers(list_output)
- list_output.scan(/^\s*identifier:\s*(\S+)/).flatten
- .select { |identifier| identifier.start_with?(IDENTIFIER_PREFIX) }
- .uniq
+ list_output.scan(/(?<![\w.-])#{Regexp.escape(IDENTIFIER_PREFIX)}-[\w.-]+/).uniq
end
def self.template
diff --git a/test/pro_tacts/test_profile.rb b/test/pro_tacts/test_profile.rb
index 0fd96e2..49ed2c1 100644
--- a/test/pro_tacts/test_profile.rb
+++ b/test/pro_tacts/test_profile.rb
@@ -66,6 +66,35 @@ class ProfileTest < Minitest::Test
], ProTacts::Profile.installed_identifiers(list_output)
end
+ def test_installed_identifiers_reads_attribute_format_output
+ list_output = <<~OUTPUT
+ alpha[1] attribute: profileIdentifier: #{ProTacts::Profile::IDENTIFIER_PREFIX}-20260818155835720a9db
+ There are 1 user configuration profiles installed for 'alpha'
+ OUTPUT
+
+ assert_equal ["#{ProTacts::Profile::IDENTIFIER_PREFIX}-20260818155835720a9db"],
+ ProTacts::Profile.installed_identifiers(list_output)
+ end
+
+ def test_installed_identifiers_reads_table_format_output
+ list_output = <<~OUTPUT
+ Profiles:
+ identifier display name
+ ------------------------------------ --------------
+ #{ProTacts::Profile::IDENTIFIER_PREFIX}-20260818ab12 pro-tacts CardDAV
+ com.example.unrelated Work
+ OUTPUT
+
+ assert_equal ["#{ProTacts::Profile::IDENTIFIER_PREFIX}-20260818ab12"],
+ ProTacts::Profile.installed_identifiers(list_output)
+ end
+
+ def test_installed_identifiers_ignores_longer_identifiers_containing_the_prefix
+ list_output = "com.example.#{ProTacts::Profile::IDENTIFIER_PREFIX}-fake\n"
+
+ assert_empty ProTacts::Profile.installed_identifiers(list_output)
+ end
+
def test_installed_identifiers_is_empty_without_ours
list_output = " identifier: com.example.unrelated\n"