| 844 | } |
| 845 | |
| 846 | export function saveGlobalConfig( |
| 847 | updater: (currentConfig: GlobalConfig) => GlobalConfig, |
| 848 | ): void { |
| 849 | if (process.env.NODE_ENV === 'test') { |
| 850 | const config = updater(TEST_GLOBAL_CONFIG_FOR_TESTING) |
| 851 | // Skip if no changes (same reference returned) |
| 852 | if (config === TEST_GLOBAL_CONFIG_FOR_TESTING) { |
| 853 | return |
| 854 | } |
| 855 | Object.assign(TEST_GLOBAL_CONFIG_FOR_TESTING, config) |
| 856 | return |
| 857 | } |
| 858 | |
| 859 | const globalConfigFile = getGlobalNcodeFile() |
| 860 | if (blockedConfigWrites.has(globalConfigFile)) { |
| 861 | const currentConfig = |
| 862 | globalConfigCache.config ?? getConfig(globalConfigFile, createDefaultGlobalConfig) |
| 863 | const config = updater(currentConfig) |
| 864 | if (config === currentConfig) { |
| 865 | return |
| 866 | } |
| 867 | writeThroughGlobalConfigCache({ |
| 868 | ...config, |
| 869 | projects: removeProjectHistory(currentConfig.projects), |
| 870 | }) |
| 871 | return |
| 872 | } |
| 873 | |
| 874 | let written: GlobalConfig | null = null |
| 875 | try { |
| 876 | const didWrite = saveConfigWithLock( |
| 877 | globalConfigFile, |
| 878 | createDefaultGlobalConfig, |
| 879 | current => { |
| 880 | const config = updater(current) |
| 881 | // Skip if no changes (same reference returned) |
| 882 | if (config === current) { |
| 883 | return current |
| 884 | } |
| 885 | written = { |
| 886 | ...config, |
| 887 | projects: removeProjectHistory(current.projects), |
| 888 | } |
| 889 | return written |
| 890 | }, |
| 891 | ) |
| 892 | // Only write-through if we actually wrote. If the auth-loss guard |
| 893 | // tripped (or the updater made no changes), the file is untouched and |
| 894 | // the cache is still valid -- touching it would corrupt the guard. |
| 895 | if (didWrite && written) { |
| 896 | writeThroughGlobalConfigCache(written) |
| 897 | } |
| 898 | } catch (error) { |
| 899 | logForDebugging(`Failed to save config with lock: ${error}`, { |
| 900 | level: 'error', |
| 901 | }) |
| 902 | // Fall back to non-locked version on error. This fallback is a race |
| 903 | // window: if another process is mid-write (or the file got truncated), |