Source code of Windows XP (NT5)
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.

383 lines
9.7 KiB

  1. //
  2. // File: tidy.js
  3. //
  4. // JScript file which walks a directory tree removing all read/write files
  5. // from the tree. It will skip over files that are in the current SD
  6. // changelist as well as copying questionable read/write files to the temp
  7. // directory in case they were really needed.
  8. //
  9. // A "questionable" file is any read/write file that is not in an object
  10. // directory (obj, objd) and is not clearly a generated file (such as a lib,
  11. // pdb, etc).
  12. //
  13. // This script assumes the current directory is the root of whatever project
  14. // you want tidied. This limitation can be removed once support for getting
  15. // the local path rather than the depot path of opened files is into SD.
  16. //
  17. // Written by Lyle Corbin, 8/18/99
  18. //
  19. var g_FSObj = new ActiveXObject("Scripting.FileSystemObject");
  20. var g_Shell = new ActiveXObject("WScript.Shell");
  21. var g_fDebug = false;
  22. var g_fVerbose = false;
  23. var g_fForce = false;
  24. var g_folderTemp;
  25. var g_cKilledFiles = 0;
  26. var g_cMovedFiles = 0;
  27. var g_cKilledDirs = 0;
  28. if (WScript.Arguments.length > 0)
  29. {
  30. var args = WScript.Arguments;
  31. var i;
  32. for (i = 0; i < args.length; i++)
  33. {
  34. switch (args(i).toLowerCase())
  35. {
  36. case '/?':
  37. case '-?':
  38. Usage();
  39. WScript.Quit(0);
  40. break;
  41. case '/d':
  42. case '-d':
  43. g_fDebug = true;
  44. break;
  45. case '/v':
  46. case '-v':
  47. g_fVerbose = true;
  48. break;
  49. case '/f':
  50. case '-f':
  51. g_fForce = true;
  52. break;
  53. }
  54. }
  55. }
  56. var tempdir = g_FSObj.GetSpecialFolder(2).Path; // Temp directory
  57. var tempfile = tempdir + '\\' + g_FSObj.GetTempName();
  58. // This limitation of running from the root of an SD client view can be removed
  59. // once support for giving the local paths to opened files is available in SD.
  60. if (!g_FSObj.FileExists('sd.ini'))
  61. {
  62. WScript.Echo('\nThis script must be run from the root directory of a SD project.\n\t(e.g. d:\\newnt\\base)');
  63. Usage();
  64. WScript.Quit(1);
  65. }
  66. if (g_fDebug)
  67. {
  68. WScript.Echo('\nDebug Mode: no actions will actually be performed!');
  69. }
  70. // First, call Source Depot and get a list of the "opened" files in this
  71. // project.
  72. var iRet = g_Shell.Run('cmd /c sd -s opened > ' + tempfile, 2, true);
  73. if (iRet != 0)
  74. {
  75. WScript.Echo('Error: SD returned failure code ' + iRet);
  76. WScript.Quit(1);
  77. }
  78. var file = g_FSObj.OpenTextFile(tempfile, 1, false); // Open for reading only
  79. // Build a list of all the files that we should skip
  80. var aOutFiles = new Array();
  81. while (!file.AtEndOfStream)
  82. {
  83. line = file.ReadLine();
  84. fields = line.split(' ');
  85. if (fields.length == 0)
  86. continue;
  87. switch (fields[0].toLowerCase())
  88. {
  89. case 'info:':
  90. filename = SDPathToLocalPath(fields[1]);
  91. filename = g_FSObj.GetAbsolutePathName(filename);
  92. // Do a sanity check on our parsing of the SD output file and verify
  93. // that all the files it gave us actually exist (except for files
  94. // marked for deletion).
  95. if (fields[3] != 'delete' && !g_FSObj.FileExists(filename))
  96. {
  97. WScript.Echo('Error parsing SD output: file ' + filename + ' marked as open doesnt exist!');
  98. WScript.Quit(1);
  99. }
  100. aOutFiles[filename.toLowerCase()] = true;
  101. break;
  102. default:
  103. break;
  104. }
  105. }
  106. file.Close();
  107. if (g_fDebug)
  108. {
  109. WScript.Echo('Files opened in this project: ');
  110. for (i in aOutFiles)
  111. {
  112. WScript.Echo('\t' + i);
  113. }
  114. }
  115. g_FSObj.DeleteFile(tempfile);
  116. if (!g_fForce)
  117. {
  118. // Make sure we have a place to archive old files
  119. var tidyFolder;
  120. tempdir += '\\tidy';
  121. if (!g_FSObj.FolderExists(tempdir))
  122. {
  123. tidyFolder = g_FSObj.CreateFolder(tempdir);
  124. }
  125. else
  126. {
  127. tidyFolder = g_FSObj.GetFolder(tempdir);
  128. }
  129. tempdir += '\\' + g_FSObj.GetFolder('.').Name;
  130. if (!g_FSObj.FolderExists(tempdir))
  131. {
  132. g_folderTemp = g_FSObj.CreateFolder(tempdir);
  133. }
  134. else
  135. {
  136. g_folderTemp = g_FSObj.GetFolder(tempdir);
  137. }
  138. }
  139. DeleteReadWriteFiles('.');
  140. if (g_fDebug)
  141. {
  142. WScript.Echo('\nDebug Mode: no actions were actually performed!');
  143. }
  144. WScript.Echo('\n' + g_cKilledFiles + ' files were deleted.');
  145. if (g_cMovedFiles > 0)
  146. {
  147. WScript.Echo(g_cMovedFiles + ' files were moved to ' + g_folderTemp.Path);
  148. WScript.Echo(' for safekeeping. If a file you need is gone, look there.');
  149. }
  150. WScript.Echo(g_cKilledDirs + ' object directories were deleted.');
  151. WScript.Echo('');
  152. WScript.Quit(0);
  153. // ************************************************************************
  154. function Usage()
  155. {
  156. WScript.Echo("\nUsage: tidy [/?dvf]\n");
  157. WScript.Echo("\t/? - Show this usage.");
  158. WScript.Echo("\t/d - Debug mode (don't delete anything).");
  159. WScript.Echo("\t/v - Verbose mode");
  160. WScript.Echo("\t/f - Don't save files not in an obj dir in %temp%\\tidy\\<projname>");
  161. WScript.Echo("");
  162. }
  163. function SDPathToLocalPath(path)
  164. {
  165. var re = new RegExp("//depot/main/", "i")
  166. var re2 = new RegExp("//depot/main/Root", "i")
  167. var index = path.lastIndexOf('#');
  168. if (index != -1)
  169. {
  170. path = path.slice(0, index);
  171. }
  172. path = path.replace(re2, '.\\');
  173. return path.replace(re, '..\\');
  174. }
  175. function DeleteReadWriteFiles(path)
  176. {
  177. var sf;
  178. var curdir;
  179. var aSubFolders = new Array();
  180. var i;
  181. var fInObjDir = false;
  182. try
  183. {
  184. curdir = g_FSObj.GetFolder(path);
  185. }
  186. catch(ex)
  187. {
  188. WScript.Echo('Error opening directory ' + path + ': ' + ex.description);
  189. return;
  190. }
  191. // Are we an object directory? If so, just delete the whole thing.
  192. if ( curdir.Name.toLowerCase() == 'obj'
  193. || curdir.Name.toLowerCase() == 'objd'
  194. || curdir.Name.toLowerCase() == 'objp') // Any other names?
  195. {
  196. g_cKilledDirs++;
  197. if (g_fVerbose)
  198. {
  199. WScript.Echo('Delete directory ' + curdir.Path);
  200. }
  201. if (!g_fDebug)
  202. {
  203. try
  204. {
  205. curdir.Delete();
  206. return;
  207. }
  208. catch(ex)
  209. {
  210. // Probably means there are read-only files in this directory.
  211. // Go through subdirs and delete read/write files explicitely
  212. // instead.
  213. //
  214. if (g_fVerbose)
  215. {
  216. WScript.Echo('Could not delete ' + curdir.Path + ': ' + ex.description);
  217. }
  218. fInObjDir = true;
  219. }
  220. }
  221. else
  222. {
  223. return;
  224. }
  225. }
  226. // First, collect the list of subfolder names
  227. sf = new Enumerator(curdir.SubFolders);
  228. for (; !sf.atEnd(); sf.moveNext())
  229. {
  230. aSubFolders[aSubFolders.length] = sf.item().Path;
  231. }
  232. // Now, walk the files in this directory and clear out read/write files.
  233. // We save these files in the temp directory (unless force is on)
  234. sf = new Enumerator(curdir.Files);
  235. for (; !sf.atEnd(); sf.moveNext())
  236. {
  237. // Is this a checked out file we want to skip?
  238. // NOTE - THIS CHECK MUST BE TOTALLY RELIABLE, OR DATA COULD BE LOST!
  239. if (aOutFiles[sf.item().Path.toLowerCase()])
  240. {
  241. WScript.Echo('Skipping opened file ' + sf.item().Path + '...');
  242. continue;
  243. }
  244. if ((sf.item().Attributes & 0x1F) == 0) // A "normal" file
  245. {
  246. var ext = g_FSObj.GetExtensionName(sf.item().Name).toLowerCase();
  247. if ( g_fForce
  248. || fInObjDir
  249. || ext == 'lib' // Don't archive files obviously not
  250. || ext == 'pdb' // user-created.
  251. || ext == 'bin'
  252. || ext == 'res'
  253. || ext == 'map'
  254. || ext == 'obj'
  255. || ext == 'pch')
  256. {
  257. g_cKilledFiles++;
  258. if (g_fVerbose)
  259. {
  260. WScript.Echo('Delete file ' + sf.item().Path);
  261. }
  262. if (!g_fDebug)
  263. {
  264. try
  265. {
  266. sf.item().Delete();
  267. }
  268. catch(ex)
  269. {
  270. WScript.Echo('Could not delete ' + sf.item().Path + ': ' + ex.description);
  271. }
  272. }
  273. }
  274. else
  275. {
  276. g_cMovedFiles++;
  277. var dest = g_folderTemp.Path + '\\' + sf.item().Name;
  278. if (g_fVerbose)
  279. {
  280. WScript.Echo('Move file ' + sf.item().Path + ' to ' + dest);
  281. }
  282. if (!g_fDebug)
  283. {
  284. try
  285. {
  286. if (g_FSObj.FileExists(dest))
  287. {
  288. g_FSObj.DeleteFile(dest);
  289. }
  290. sf.item().Move(dest);
  291. }
  292. catch(ex)
  293. {
  294. WScript.Echo('Could not move ' + sf.item().Path + ': ' + ex.description);
  295. }
  296. }
  297. }
  298. }
  299. }
  300. // Now, recurse into subdirectories
  301. for (i = 0; i < aSubFolders.length; i++)
  302. {
  303. // Is the subdirectory the root of another SD project (determined by
  304. // the existence of an sd.ini file)? If so, skip it.
  305. // We only check this for directories that are immediate children
  306. // of the starting directory.
  307. if (path != '.' || !g_FSObj.FileExists(aSubFolders[i] + '\\sd.ini'))
  308. {
  309. DeleteReadWriteFiles(aSubFolders[i]);
  310. }
  311. else if (g_fVerbose || g_fDebug)
  312. {
  313. WScript.Echo('Directory ' + aSubFolders[i] + ' is the root of another project! Skipping...');
  314. }
  315. }
  316. }