Skip to content

Commit

Permalink
Exclude project files (when configured to save scenes and events in d…
Browse files Browse the repository at this point in the history
…ifferent files) from watcher (#5885)

Also, exclude git files when using git versioning.
  • Loading branch information
AlexandreSi authored Nov 15, 2023
1 parent 4ea6fb7 commit c2dfe57
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 51 deletions.
62 changes: 41 additions & 21 deletions newIDE/app/src/MainFrame/ResourcesWatcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,47 @@ import PreferencesContext from './Preferences/PreferencesContext';
import { type StorageProvider, type FileMetadata } from '../ProjectsStorage';
import { type EditorTabsState } from './EditorTabs/EditorTabsHandler';

const useResourcesWatcher = (
const useResourcesWatcher = ({
getStorageProvider,
fileMetadata,
editorTabs,
isProjectSplitInMultipleFiles,
}: {|
getStorageProvider: () => StorageProvider,
fileMetadata: ?FileMetadata,
editorTabs: EditorTabsState
) => {
editorTabs: EditorTabsState,
isProjectSplitInMultipleFiles: boolean,
|}) => {
const {
values: { watchProjectFolderFilesForLocalProjects },
} = React.useContext(PreferencesContext);
// Whole fileMetadata object is not used because lastModifiedDate changes on save
// thus triggering the effect.
const fileIdentifier = fileMetadata ? fileMetadata.fileIdentifier : null;

// Callbacks are extracted from editorTabs to avoid redefining informEditorsResourceExternallyChanged
// thus triggering the effect on each active tab change (stored in editorTabs).
const callbacks = React.useMemo(
() =>
editorTabs.editors
.map(
editorTab =>
editorTab.editorRef &&
editorTab.editorRef.editor &&
// Each editor container has an accessible editor property.
// $FlowFixMe[prop-missing]
editorTab.editorRef.editor.onResourceExternallyChanged
)
.filter(Boolean),
[editorTabs.editors]
);

const informEditorsResourceExternallyChanged = React.useCallback(
(resourceInfo: {| identifier: string |}) => {
ResourcesLoader.burstAllUrlsCache();
editorTabs.editors.forEach(editorTab => {
if (
editorTab.editorRef &&
editorTab.editorRef.editor &&
editorTab.editorRef.editor.onResourceExternallyChanged
) {
// Each editor container has an accessible editor property.
// $FlowFixMe[not-a-function]
editorTab.editorRef.editor.onResourceExternallyChanged(resourceInfo);
}
});
callbacks.forEach(callback => callback(resourceInfo));
},
[editorTabs]
[callbacks]
);

React.useEffect(
Expand All @@ -41,19 +57,23 @@ const useResourcesWatcher = (
) {
return;
}
if (fileMetadata && storageProvider.setupResourcesWatcher) {
const unsubscribe = storageProvider.setupResourcesWatcher(
fileMetadata,
informEditorsResourceExternallyChanged
);
if (fileIdentifier && storageProvider.setupResourcesWatcher) {
const unsubscribe = storageProvider.setupResourcesWatcher({
fileIdentifier,
callback: informEditorsResourceExternallyChanged,
options: {
isProjectSplitInMultipleFiles,
},
});
return unsubscribe;
}
},
[
fileMetadata,
fileIdentifier,
informEditorsResourceExternallyChanged,
getStorageProvider,
watchProjectFolderFilesForLocalProjects,
isProjectSplitInMultipleFiles,
]
);
};
Expand Down
11 changes: 7 additions & 4 deletions newIDE/app/src/MainFrame/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -501,11 +501,14 @@ const MainFrame = (props: Props) => {
ensureResourcesAreFetched,
renderResourceFetcherDialog,
} = useResourceFetcher({ resourceFetcher });
useResourcesWatcher(
useResourcesWatcher({
getStorageProvider,
currentFileMetadata,
state.editorTabs
);
fileMetadata: currentFileMetadata,
editorTabs: state.editorTabs,
isProjectSplitInMultipleFiles: currentProject
? currentProject.isFolderProject()
: false,
});

/**
* This reference is useful to get the current opened project,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
// @flow
import optionalRequire from '../../Utils/OptionalRequire';
import { type FileMetadata } from '..';
import debounce from 'lodash/debounce';
import wrap from 'lodash/wrap';
import memoize from 'lodash/memoize';
import { splittedProjectFolderNames } from './LocalProjectWriter';

const path = optionalRequire('path');
const electron = optionalRequire('electron');
const ipcRenderer = electron ? electron.ipcRenderer : null;

export const setupResourcesWatcher =
ipcRenderer && path
? (
fileMetadata: FileMetadata,
callback: ({| identifier: string |}) => void
) => {
? ({
fileIdentifier,
callback,
options,
}: {
fileIdentifier: string,
callback: ({| identifier: string |}) => void,
options?: {| isProjectSplitInMultipleFiles: boolean |},
}) => {
// We can't just debounce the whole callback, it has to be done file-wise,
// otherwise we would miss all the debounced calls but the last one.
// See https://stackoverflow.com/questions/28787436/debounce-a-function-with-argument
Expand All @@ -34,26 +39,29 @@ export const setupResourcesWatcher =
),
(getMemoizedFunc, obj) => getMemoizedFunc(obj)(obj)
);
const folderPath = path.dirname(fileMetadata.fileIdentifier);
const gameFile = path.basename(fileMetadata.fileIdentifier);
const folderPath = path.dirname(fileIdentifier);
const gameFile = path.basename(fileIdentifier);
const autosaveFile = gameFile + '.autosave';
ipcRenderer.on('project-file-changed', (event, path) => {
// TODO: Is it safe to let it like that since the OS could for some reason
// do never-ending operations on the folder or its children, making the debounce
// never ending.
debouncedCallback(path);
});
const ignore = [
'**/.DS_Store', // macOS folder attributes file
'**/.git/**', // For projects using git as a versioning tool.
path.join(folderPath, gameFile),
path.join(folderPath, autosaveFile),
];
if (options && options.isProjectSplitInMultipleFiles) {
ignore.push(`{${splittedProjectFolderNames.join(',')}}/*.json`);
}
const subscriptionIdPromise = ipcRenderer.invoke(
'local-filesystem-watcher-setup',

folderPath,
JSON.stringify({
ignore: [
'**/.DS_Store', // macOS folder attributes file
'**/.git/**', // For projects using git as a versioning tool.
path.join(folderPath, gameFile),
path.join(folderPath, autosaveFile),
],
ignore,
})
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ const path = optionalRequire('path');
const remote = optionalRequire('@electron/remote');
const dialog = remote ? remote.dialog : null;

export const splittedProjectFolderNames = [
'layouts',
'externalLayouts',
'externalEvents',
'eventsFunctionsExtensions',
];

const checkFileContent = (filePath: string, expectedContent: string) => {
const time = performance.now();
return new Promise((resolve, reject) => {
Expand All @@ -42,7 +49,7 @@ const checkFileContent = (filePath: string, expectedContent: string) => {
});
};

export const writeAndCheckFile = async (
const writeAndCheckFile = async (
content: string,
filePath: string
): Promise<void> => {
Expand Down Expand Up @@ -75,13 +82,9 @@ const writeProjectFiles = (
pathSeparator: '/',
getArrayItemReferenceName: getSlugifiedUniqueNameFromProperty('name'),
shouldSplit: splitPaths(
new Set([
'/layouts/*',
'/externalLayouts/*',
'/externalEvents/*',
'/layouts/*',
'/eventsFunctionsExtensions/*',
])
new Set(
splittedProjectFolderNames.map(folderName => `/${folderName}/*`)
)
),
isReferenceMagicPropertyName: '__REFERENCE_TO_SPLIT_OBJECT',
});
Expand Down
9 changes: 5 additions & 4 deletions newIDE/app/src/ProjectsStorage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,9 @@ export type StorageProvider = {|
authenticatedUser: AuthenticatedUser,
|}) => ResourcesActionsMenuBuilder,
/** Resources external changes */
setupResourcesWatcher?: (
fileMetadata: FileMetadata,
callback: ({| identifier: string |}) => void
) => () => void,
setupResourcesWatcher?: ({|
fileIdentifier: string,
callback: ({| identifier: string |}) => void,
options?: any,
|}) => () => void,
|};

0 comments on commit c2dfe57

Please sign in to comment.