Skip to content

Improve site path uniqueness validation using normalized comparisons - #976

Merged
bcotrim merged 3 commits into
trunkfrom
fix/path_uniqueness_check_windows
Mar 5, 2025
Merged

Improve site path uniqueness validation using normalized comparisons#976
bcotrim merged 3 commits into
trunkfrom
fix/path_uniqueness_check_windows

Conversation

@bcotrim

@bcotrim bcotrim commented Feb 25, 2025

Copy link
Copy Markdown
Contributor

Related issues

Proposed Changes

  • Uses generateProposedSitePath to check if the path is available for a new site
  • Updated generateSiteName to be async to support proper path validation
  • Enhanced reliability of site path uniqueness validation

Testing Instructions

  • Create multiple WordPress instances with similar names
  • Verify that path uniqueness is correctly validated across platforms
  • Test on case-sensitive and case-insensitive filesystems if possible
  • Ensure site creation works properly with the updated async flow

Pre-merge Checklist

  • Have you checked for TypeScript, React or other console errors?
@bcotrim
bcotrim requested a review from a team February 25, 2025 09:37
@bcotrim

bcotrim commented Feb 25, 2025

Copy link
Copy Markdown
Contributor Author

@Automattic/yolo
We could potential just change the isPathEnding function to something like

function isPathEndingWith(path: string, suffix: string): boolean {
  // Normalize paths by standardizing separators and case
  const normalize = (p: string) => p.toLowerCase().replace(/[\\\/]+/g, '/');
  return normalize(path).endsWith(normalize(suffix));
}

I opted for consistency and reliability, that this solution doesn't offer, but at the cost of some more calls to the IPC.
Since this operation only happens when creating a site, I don't think performance will be an issue, but let me know what you think.

@wojtekn wojtekn left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I tested it on Windows and Mac and it works fine.

@fredrikekelund fredrikekelund left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Making generateSiteName async so that we can properly validate the proposed path seems to work well, but I think we should consider my proposal of dropping isPathEndingWith in favor of generateProposedSitePath

Comment thread src/lib/generate-site-name.ts Outdated
Comment on lines +31 to +37
const sanitizedPath = sanitizeFolderName( name );
return ! usedSites.some( ( site ) => site.path.toLowerCase().endsWith( '/' + sanitizedPath ) );
for ( const site of usedSites ) {
if ( await getIpcApi().isPathEndingWith( site.path, `/${ sanitizedPath }` ) ) {
return false;
}
}
return true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

		const { isEmpty } = await getIpcApi().generateProposedSitePath( name );
		return isEmpty;

Could we do something like this instead? It seems like we're kind of duplicating logic now between generateProposedSitePath and isPathEndingWith now, and this solution seems to work well in my testing.

This would also allow us to remove isPathEndingWith altogether, simplifying this PR.

Comment thread src/components/onboarding.tsx Outdated
Comment on lines +78 to +87
useEffect( () => {
const run = async () => {
const { path, name, isWordPress } = await getIpcApi().generateProposedSitePath(
generateSiteName( [] )
);
setSiteName( name );
setProposedSitePath( path );
setSitePath( '' );
setError( '' );
setDoesPathContainWordPress( isWordPress );
};
run();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [] );
const run = async () => {
const siteName = await generateSiteName( [] );
const { path, name, isWordPress } = await getIpcApi().generateProposedSitePath( siteName );
setSiteName( name );
setProposedSitePath( path );
setSitePath( '' );
setError( '' );
setDoesPathContainWordPress( isWordPress );
};
run();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't understand this change. Why should we move this logic outside the useEffect callback? 🤔

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We shouldn't 😅
I rolled back the change.

@bcotrim

bcotrim commented Mar 5, 2025

Copy link
Copy Markdown
Contributor Author

@fredrikekelund thanks for the suggestion, I agree that's an improvement!
I tested the changes on mac and windows and it seems to be working as expected.

@bcotrim
bcotrim requested a review from fredrikekelund March 5, 2025 15:17

@fredrikekelund fredrikekelund left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM and works as expected 👍

setDoesPathContainWordPress( isWordPress );
};
run();
// eslint-disable-next-line react-hooks/exhaustive-deps

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's bring this line back to signal that we are intentionally excluding those effect dependecies.

@bcotrim
bcotrim merged commit 4c3e8a6 into trunk Mar 5, 2025
@bcotrim
bcotrim deleted the fix/path_uniqueness_check_windows branch March 5, 2025 17:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants