Skip to content

Add --strip-uuid flag to remove UUIDs from exported filenames#19

Open
davidbean-hash wants to merge 1 commit into
masterfrom
devin/1779386076-strip-uuid-option
Open

Add --strip-uuid flag to remove UUIDs from exported filenames#19
davidbean-hash wants to merge 1 commit into
masterfrom
devin/1779386076-strip-uuid-option

Conversation

@davidbean-hash
Copy link
Copy Markdown
Owner

@davidbean-hash davidbean-hash commented May 21, 2026

Change Description:

Implements ChargePoint/xcparse#42: Option to remove UUID from image filenames.

Currently exported screenshots have UUIDs embedded in their names like Screenshot_1_BC641069-A876-42D7-AD9E-54D7CB3B984D.heic. This PR adds a --strip-uuid flag to the screenshots and attachments commands that strips the _<UUID> portion from filenames during export, producing cleaner names like Screenshot_1.heic.

Changes

  • AttachmentExportOptions (XCPParser.swift): Added stripUUID: Bool property
  • XCPParser (XCPParser.swift):
    • Added filenameByStrippingUUID(from:) static method using regex pattern _[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}
    • Updated exportAttachments to accept stripUUID parameter and handle collision resolution (appends _2, _3, etc.)
    • When stripUUID is enabled, uses XCResultToolCommand.Export(id:outputPath:type:) with the modified filename instead of the attachment-based initializer
  • ScreenshotsCommand: Registered --strip-uuid CLI flag
  • AttachmentsCommand: Registered --strip-uuid CLI flag

Usage

xcparse screenshots --strip-uuid /path/to/Test.xcresult /path/to/output
xcparse attachments --strip-uuid /path/to/Test.xcresult /path/to/output

Collision handling

When stripping UUIDs produces duplicate filenames (e.g., two Screenshot_1.heic), a counter suffix is appended: Screenshot_1.heic, Screenshot_1_2.heic, Screenshot_1_3.heic, etc.

Test Plan/Testing Performed:

Added StripUUIDTests.swift with 11 unit test cases covering:

  • Typical screenshot filename with UUID (Screenshot_1_BC641069-...) → Screenshot_1.heic
  • Lowercase UUIDs
  • Multiple UUIDs in a single filename
  • Filenames without UUIDs (unchanged)
  • Filenames without extensions
  • Edge case: filename is only a UUID (returns original to avoid empty name)
  • Partial/incomplete UUIDs (not stripped)
  • Various file extensions (.heic, .png, .jpeg)

Link to Devin session: https://app.devin.ai/sessions/a11e28d22c614743849b525b99f64aef
Requested by: @davidbean-hash


Open in Devin Review

Implements ChargePoint#42: Option to remove UUID from image filenames.

- Add stripUUID property to AttachmentExportOptions
- Add --strip-uuid CLI flag to both ScreenshotsCommand and AttachmentsCommand
- Add XCPParser.filenameByStrippingUUID(from:) static method using regex
- Handle filename collisions by appending _2, _3, etc. counter suffix
- Add StripUUIDTests with 11 test cases covering various filename patterns

Co-Authored-By: david.bean <david.bean@cognition.ai>
@devin-ai-integration
Copy link
Copy Markdown

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 3 additional findings in Devin Review.

Open in Devin Review

Comment on lines +321 to +331
let count = usedFilenames[strippedFilename, default: 0]
usedFilenames[strippedFilename] = count + 1
if count > 0 {
let nameWithoutExtension = (strippedFilename as NSString).deletingPathExtension
let fileExtension = (strippedFilename as NSString).pathExtension
if fileExtension.isEmpty {
strippedFilename = "\(nameWithoutExtension)_\(count + 1)"
} else {
strippedFilename = "\(nameWithoutExtension)_\(count + 1).\(fileExtension)"
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Deduplication suffix can collide with another file's natural stripped name, causing silent overwrite

The usedFilenames dictionary tracks only the pre-dedup stripped filename, not the actual output filename after a _N suffix is appended. This means a collision-avoidance name can overwrite a different file that naturally has that name.

Concrete collision scenario

Consider three attachments in the same directory:

  • File A: Screenshot_UUID1.png → strips to Screenshot.png
  • File B: Screenshot_UUID2.png → strips to Screenshot.png
  • File C: Screenshot_2_UUID3.png → strips to Screenshot_2.png

Processing:

  1. File A → usedFilenames["Screenshot.png"] = 1 → output: Screenshot.png
  2. File B → count=1 → suffix _2 → output: Screenshot_2.png
  3. File C → usedFilenames["Screenshot_2.png"] = 1, count=0 → no suffix → output: Screenshot_2.pngoverwrites File B!

The suffixed output filenames are never checked against or added to usedFilenames, so the code cannot detect that Screenshot_2.png is already in use.

Prompt for agents
In XCPParser.exportAttachments (around lines 312-331), the usedFilenames dictionary tracks stripped base filenames, but the collision-avoidance suffixed filenames (like Screenshot_2.png) are never registered in the dictionary. This means another file that naturally strips to that same name will silently overwrite it.

The fix is to track the actual output filenames rather than just the pre-dedup base names. One approach: change usedFilenames to a Set<String> that stores the final output filenames. When generating a dedup suffix, keep incrementing the counter until the resulting filename is not in the set. Always insert the final output filename into the set. For example:

var usedFilenames = Set<String>()
...
var candidate = strippedFilename
var counter = 2
while usedFilenames.contains(candidate) {
    // generate candidate with _counter suffix
    counter += 1
}
usedFilenames.insert(candidate)
strippedFilename = candidate
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant