You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

593 lines
14 KiB

4 years ago
4 years ago
4 years ago
4 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software: you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation, either version 3 of the License, or (at your
  9. * option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <wx/filename.h>
  20. #include <wx/stdpaths.h>
  21. #include <wx/string.h>
  22. #include <wx/utils.h>
  23. #include <kiplatform/environment.h>
  24. #include <paths.h>
  25. #include <config.h>
  26. #include <build_version.h>
  27. #include <macros.h>
  28. #include <wx_filename.h>
  29. // lowercase or pretty case depending on platform
  30. #if defined( __WXMAC__ ) || defined( __WXMSW__ )
  31. #define KICAD_PATH_STR wxT( "KiCad" )
  32. #else
  33. #define KICAD_PATH_STR wxT( "kicad" )
  34. #endif
  35. void PATHS::getUserDocumentPath( wxFileName& aPath )
  36. {
  37. wxString envPath;
  38. if( wxGetEnv( wxT( "KICAD_DOCUMENTS_HOME" ), &envPath ) )
  39. aPath.AssignDir( envPath );
  40. else
  41. aPath.AssignDir( KIPLATFORM::ENV::GetDocumentsPath() );
  42. aPath.AppendDir( KICAD_PATH_STR );
  43. aPath.AppendDir( GetMajorMinorVersion().ToStdString() );
  44. }
  45. wxString PATHS::GetUserPluginsPath()
  46. {
  47. wxFileName tmp;
  48. getUserDocumentPath( tmp );
  49. tmp.AppendDir( wxT( "plugins" ) );
  50. return tmp.GetPath();
  51. }
  52. wxString PATHS::GetUserScriptingPath()
  53. {
  54. wxFileName tmp;
  55. getUserDocumentPath( tmp );
  56. tmp.AppendDir( wxT( "scripting" ) );
  57. return tmp.GetPath();
  58. }
  59. wxString PATHS::GetUserTemplatesPath()
  60. {
  61. wxFileName tmp;
  62. getUserDocumentPath( tmp );
  63. tmp.AppendDir( wxT( "template" ) );
  64. return tmp.GetPathWithSep();
  65. }
  66. wxString PATHS::GetDefaultUserSymbolsPath()
  67. {
  68. wxFileName tmp;
  69. getUserDocumentPath( tmp );
  70. tmp.AppendDir( wxT( "symbols" ) );
  71. return tmp.GetPath();
  72. }
  73. wxString PATHS::GetDefaultUserFootprintsPath()
  74. {
  75. wxFileName tmp;
  76. getUserDocumentPath( tmp );
  77. tmp.AppendDir( wxT( "footprints" ) );
  78. return tmp.GetPath();
  79. }
  80. wxString PATHS::GetDefaultUser3DModelsPath()
  81. {
  82. wxFileName tmp;
  83. getUserDocumentPath( tmp );
  84. tmp.AppendDir( wxT( "3dmodels" ) );
  85. return tmp.GetPath();
  86. }
  87. wxString PATHS::GetDefault3rdPartyPath()
  88. {
  89. wxFileName tmp;
  90. getUserDocumentPath( tmp );
  91. tmp.AppendDir( wxT( "3rdparty" ) );
  92. return tmp.GetPath();
  93. }
  94. wxString PATHS::GetDefaultUserProjectsPath()
  95. {
  96. wxFileName tmp;
  97. getUserDocumentPath( tmp );
  98. tmp.AppendDir( wxT( "projects" ) );
  99. return tmp.GetPath();
  100. }
  101. wxString PATHS::GetStockDataPath( bool aRespectRunFromBuildDir )
  102. {
  103. wxString path;
  104. if( aRespectRunFromBuildDir && wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
  105. {
  106. // Allow debugging from build dir by placing relevant files/folders in the build root
  107. #if defined( __WXMAC__ )
  108. wxFileName fn = wxStandardPaths::Get().GetExecutablePath();
  109. fn.RemoveLastDir();
  110. fn.RemoveLastDir();
  111. fn.RemoveLastDir();
  112. fn.RemoveLastDir();
  113. path = fn.GetPath();
  114. #elif defined( __WXMSW__ )
  115. path = getWindowsKiCadRoot();
  116. #else
  117. path = GetExecutablePath() + wxT( ".." );
  118. #endif
  119. }
  120. else if( wxGetEnv( wxT( "KICAD_STOCK_DATA_HOME" ), &path ) && !path.IsEmpty() )
  121. {
  122. return path;
  123. }
  124. else
  125. {
  126. #if defined( __WXMAC__ )
  127. path = GetOSXKicadDataDir();
  128. #elif defined( __WXMSW__ )
  129. path = getWindowsKiCadRoot() + wxT( "share/kicad" );
  130. #else
  131. path = wxString::FromUTF8Unchecked( KICAD_DATA );
  132. #endif
  133. }
  134. return path;
  135. }
  136. #ifdef __WXMSW__
  137. /**
  138. * Gets the stock (install) data path, which is the base path for things like scripting, etc
  139. */
  140. wxString PATHS::GetWindowsBaseSharePath()
  141. {
  142. return getWindowsKiCadRoot() + wxT( "share\\" );
  143. }
  144. #endif
  145. wxString PATHS::GetStockEDALibraryPath()
  146. {
  147. wxString path;
  148. #if defined( __WXMAC__ )
  149. path = GetOSXKicadMachineDataDir();
  150. #elif defined( __WXMSW__ )
  151. path = GetStockDataPath( false );
  152. #else
  153. path = wxString::FromUTF8Unchecked( KICAD_LIBRARY_DATA );
  154. #endif
  155. return path;
  156. }
  157. wxString PATHS::GetStockSymbolsPath()
  158. {
  159. wxString path;
  160. path = GetStockEDALibraryPath() + wxT( "/symbols" );
  161. return path;
  162. }
  163. wxString PATHS::GetStockFootprintsPath()
  164. {
  165. wxString path;
  166. path = GetStockEDALibraryPath() + wxT( "/footprints" );
  167. return path;
  168. }
  169. wxString PATHS::GetStock3dmodelsPath()
  170. {
  171. wxString path;
  172. path = GetStockEDALibraryPath() + wxT( "/3dmodels" );
  173. return path;
  174. }
  175. wxString PATHS::GetStockScriptingPath()
  176. {
  177. wxString path;
  178. path = GetStockDataPath() + wxT( "/scripting" );
  179. return path;
  180. }
  181. wxString PATHS::GetStockTemplatesPath()
  182. {
  183. wxString path;
  184. path = GetStockEDALibraryPath() + wxT( "/template" );
  185. return path;
  186. }
  187. wxString PATHS::GetLocaleDataPath()
  188. {
  189. wxString path;
  190. path = GetStockDataPath() + wxT( "/internat" );
  191. return path;
  192. }
  193. wxString PATHS::GetStockPluginsPath()
  194. {
  195. wxFileName fn;
  196. #if defined( __WXMSW__ )
  197. fn.AssignDir( GetExecutablePath() );
  198. fn.AppendDir( wxT( "scripting" ) );
  199. #else
  200. fn.AssignDir( PATHS::GetStockDataPath( false ) );
  201. #endif
  202. fn.AppendDir( wxT( "plugins" ) );
  203. return fn.GetPathWithSep();
  204. }
  205. wxString PATHS::GetStockPlugins3DPath()
  206. {
  207. wxFileName fn;
  208. #if defined( __WXMSW__ )
  209. if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
  210. {
  211. fn.AssignDir( getWindowsKiCadRoot() );
  212. }
  213. else
  214. {
  215. fn.AssignDir( GetExecutablePath() );
  216. }
  217. fn.AppendDir( wxT( "plugins" ) );
  218. #elif defined( __WXMAC__ )
  219. fn.Assign( wxStandardPaths::Get().GetPluginsDir(), wxEmptyString );
  220. // This must be mapped to main bundle for everything but kicad.app
  221. const wxArrayString dirs = fn.GetDirs();
  222. // Check if we are the main kicad binary. in this case, the path will be
  223. // /path/to/bundlename.app/Contents/PlugIns
  224. // If we are an aux binary, the path will be something like
  225. // /path/to/bundlename.app/Contents/Applications/<standalone>.app/Contents/PlugIns
  226. if( dirs.GetCount() >= 6 &&
  227. dirs[dirs.GetCount() - 4] == wxT( "Applications" ) &&
  228. dirs[dirs.GetCount() - 6].Lower().EndsWith( wxT( "app" ) ) )
  229. {
  230. fn.RemoveLastDir();
  231. fn.RemoveLastDir();
  232. fn.RemoveLastDir();
  233. fn.RemoveLastDir();
  234. fn.AppendDir( wxT( "PlugIns" ) );
  235. }
  236. #else
  237. // KICAD_PLUGINDIR = CMAKE_INSTALL_FULL_LIBDIR path is the absolute path
  238. // corresponding to the install path used for constructing KICAD_USER_PLUGIN
  239. wxString tfname = wxString::FromUTF8Unchecked( KICAD_PLUGINDIR );
  240. fn.Assign( tfname, "" );
  241. fn.AppendDir( wxT( "kicad" ) );
  242. fn.AppendDir( wxT( "plugins" ) );
  243. #endif
  244. fn.AppendDir( wxT( "3d" ) );
  245. return fn.GetPathWithSep();
  246. }
  247. wxString PATHS::GetStockDemosPath()
  248. {
  249. wxFileName fn;
  250. fn.AssignDir( PATHS::GetStockDataPath( false ) );
  251. fn.AppendDir( wxT( "demos" ) );
  252. return fn.GetPathWithSep();
  253. }
  254. wxString PATHS::GetUserCachePath()
  255. {
  256. wxString envPath;
  257. wxFileName tmp;
  258. tmp.AssignDir( KIPLATFORM::ENV::GetUserCachePath() );
  259. // Use KICAD_CACHE_HOME to allow the user to force a specific cache path.
  260. if( wxGetEnv( wxT( "KICAD_CACHE_HOME" ), &envPath ) && !envPath.IsEmpty() )
  261. {
  262. // Override the assignment above with KICAD_CACHE_HOME
  263. tmp.AssignDir( envPath );
  264. }
  265. tmp.AppendDir( KICAD_PATH_STR );
  266. tmp.AppendDir( GetMajorMinorVersion().ToStdString() );
  267. return tmp.GetPathWithSep();
  268. }
  269. wxString PATHS::GetDocumentationPath()
  270. {
  271. wxString path;
  272. #if defined( __WXMAC__ )
  273. path = GetOSXKicadDataDir();
  274. #elif defined( __WXMSW__ )
  275. path = getWindowsKiCadRoot() + wxT( "share/doc/kicad" );
  276. #else
  277. path = wxString::FromUTF8Unchecked( KICAD_DOCS );
  278. #endif
  279. return path;
  280. }
  281. wxString PATHS::GetInstanceCheckerPath()
  282. {
  283. wxFileName path;
  284. path.AssignDir( wxStandardPaths::Get().GetTempDir() );
  285. path.AppendDir( "org.kicad.kicad" );
  286. path.AppendDir( "instances" );
  287. return path.GetPathWithSep();
  288. }
  289. wxString PATHS::GetLogsPath()
  290. {
  291. wxFileName tmp;
  292. getUserDocumentPath( tmp );
  293. tmp.AppendDir( wxT( "logs" ) );
  294. return tmp.GetPath();
  295. }
  296. bool PATHS::EnsurePathExists( const wxString& aPath )
  297. {
  298. wxFileName path( aPath );
  299. if( !path.MakeAbsolute() )
  300. {
  301. return false;
  302. }
  303. if( !wxFileName::DirExists( aPath ) )
  304. {
  305. if( !wxFileName::Mkdir( aPath, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
  306. {
  307. return false;
  308. }
  309. }
  310. return true;
  311. }
  312. void PATHS::EnsureUserPathsExist()
  313. {
  314. EnsurePathExists( GetUserCachePath() );
  315. EnsurePathExists( GetUserPluginsPath() );
  316. EnsurePathExists( GetUserScriptingPath() );
  317. EnsurePathExists( GetUserTemplatesPath() );
  318. EnsurePathExists( GetDefaultUserProjectsPath() );
  319. EnsurePathExists( GetDefaultUserSymbolsPath() );
  320. EnsurePathExists( GetDefaultUserFootprintsPath() );
  321. EnsurePathExists( GetDefaultUser3DModelsPath() );
  322. EnsurePathExists( GetDefault3rdPartyPath() );
  323. }
  324. #ifdef __WXMAC__
  325. wxString PATHS::GetOSXKicadUserDataDir()
  326. {
  327. // According to wxWidgets documentation for GetUserDataDir:
  328. // Mac: ~/Library/Application Support/appname
  329. wxFileName udir( wxStandardPaths::Get().GetUserDataDir(), wxEmptyString );
  330. // Since appname is different if started via launcher or standalone binary
  331. // map all to "kicad" here
  332. udir.RemoveLastDir();
  333. udir.AppendDir( wxT( "kicad" ) );
  334. return udir.GetPath();
  335. }
  336. wxString PATHS::GetOSXKicadMachineDataDir()
  337. {
  338. // 6.0 forward: Same as the main data dir
  339. return GetOSXKicadDataDir();
  340. }
  341. wxString PATHS::GetOSXKicadDataDir()
  342. {
  343. // According to wxWidgets documentation for GetDataDir:
  344. // Mac: appname.app/Contents/SharedSupport bundle subdirectory
  345. wxFileName ddir( wxStandardPaths::Get().GetDataDir(), wxEmptyString );
  346. // This must be mapped to main bundle for everything but kicad.app
  347. const wxArrayString dirs = ddir.GetDirs();
  348. // Check if we are the main kicad binary. in this case, the path will be
  349. // /path/to/bundlename.app/Contents/SharedSupport
  350. // If we are an aux binary, the path will be something like
  351. // /path/to/bundlename.app/Contents/Applications/<standalone>.app/Contents/SharedSupport
  352. if( dirs.GetCount() >= 6 &&
  353. dirs[dirs.GetCount() - 4] == wxT( "Applications" ) &&
  354. dirs[dirs.GetCount() - 6].Lower().EndsWith( wxT( "app" ) ) )
  355. {
  356. ddir.RemoveLastDir();
  357. ddir.RemoveLastDir();
  358. ddir.RemoveLastDir();
  359. ddir.RemoveLastDir();
  360. ddir.AppendDir( wxT( "SharedSupport" ) );
  361. }
  362. return ddir.GetPath();
  363. }
  364. #endif
  365. #ifdef __WXMSW__
  366. wxString PATHS::GetWindowsFontConfigDir()
  367. {
  368. wxFileName fn;
  369. fn.AssignDir( getWindowsKiCadRoot() );
  370. fn.AppendDir( wxS( "etc" ) );
  371. fn.AppendDir( wxS( "fonts" ) );
  372. return fn.GetPathWithSep();
  373. }
  374. wxString PATHS::getWindowsKiCadRoot()
  375. {
  376. wxFileName root( GetExecutablePath() + wxT( "/../" ) );
  377. root.MakeAbsolute();
  378. return root.GetPathWithSep();
  379. }
  380. #endif
  381. wxString PATHS::GetUserSettingsPath()
  382. {
  383. static wxString user_settings_path;
  384. if( user_settings_path.empty() )
  385. user_settings_path = CalculateUserSettingsPath();
  386. return user_settings_path;
  387. }
  388. wxString PATHS::CalculateUserSettingsPath( bool aIncludeVer, bool aUseEnv )
  389. {
  390. wxFileName cfgpath;
  391. // http://docs.wxwidgets.org/3.0/classwx_standard_paths.html#a7c7cf595d94d29147360d031647476b0
  392. wxString envstr;
  393. if( aUseEnv && wxGetEnv( wxT( "KICAD_CONFIG_HOME" ), &envstr ) && !envstr.IsEmpty() )
  394. {
  395. // Override the assignment above with KICAD_CONFIG_HOME
  396. cfgpath.AssignDir( envstr );
  397. }
  398. else
  399. {
  400. cfgpath.AssignDir( KIPLATFORM::ENV::GetUserConfigPath() );
  401. cfgpath.AppendDir( TO_STR( KICAD_CONFIG_DIR ) );
  402. }
  403. if( aIncludeVer )
  404. cfgpath.AppendDir( GetMajorMinorVersion().ToStdString() );
  405. return cfgpath.GetPath();
  406. }
  407. const wxString& PATHS::GetExecutablePath()
  408. {
  409. static wxString exe_path;
  410. if( exe_path.empty() )
  411. {
  412. wxString bin_dir = wxStandardPaths::Get().GetExecutablePath();
  413. #ifdef __WXMAC__
  414. // On OSX GetExecutablePath() will always point to main
  415. // bundle directory, e.g., /Applications/kicad.app/
  416. wxFileName fn( bin_dir );
  417. WX_FILENAME::ResolvePossibleSymlinks( fn );
  418. if( fn.GetName() == wxT( "kicad" ) || fn.GetName() == wxT( "kicad-cli" ) )
  419. {
  420. // kicad launcher, so just remove the Contents/MacOS part
  421. fn.RemoveLastDir();
  422. fn.RemoveLastDir();
  423. }
  424. else
  425. {
  426. // standalone binaries live in Contents/Applications/<standalone>.app/Contents/MacOS
  427. fn.RemoveLastDir();
  428. fn.RemoveLastDir();
  429. fn.RemoveLastDir();
  430. fn.RemoveLastDir();
  431. fn.RemoveLastDir();
  432. }
  433. bin_dir = fn.GetPath() + wxT( "/" );
  434. #else
  435. // Use unix notation for paths. I am not sure this is a good idea,
  436. // but it simplifies compatibility between Windows and Unices.
  437. // However it is a potential problem in path handling under Windows.
  438. bin_dir.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP );
  439. // Remove file name form command line:
  440. while( bin_dir.Last() != '/' && !bin_dir.IsEmpty() )
  441. bin_dir.RemoveLast();
  442. #endif
  443. exe_path = bin_dir;
  444. }
  445. return exe_path;
  446. }