Newer
Older
dub_jkp / test / issue2234-copy-read-only-files.script.d
@Bastiaan Veelo Bastiaan Veelo on 13 Jun 2022 3 KB Fix #2234, make copies writable.
  1. /+ dub.json: {
  2. "name": "issue2234_copy_read_only_files"
  3. } +/
  4.  
  5. /*
  6. When DUB copies read-only files to the targetPath, the read-only flag must be
  7. removed. If not, any subsequent copy operations will fail.
  8.  
  9. Version control systems such as Git Large File Storage typically mark binary
  10. files as read-only, to prevent simultaneous edits in unmergeable formats.
  11. */
  12.  
  13. module issue2234_copy_read_only_files.script;
  14.  
  15. import
  16. std.algorithm.searching,
  17. std.algorithm.iteration,
  18. std.stdio, std.process, std.path, std.file;
  19.  
  20. int main()
  21. {
  22. const project_dir = buildPath(__FILE_FULL_PATH__.dirName, "issue2234-copy-read-only-files");
  23. const deployment_dir = buildPath(project_dir, "bin");
  24. auto deployables = dirEntries(buildPath(project_dir, "files"), "*", SpanMode.depth).filter!isFile;
  25.  
  26. // Prepare environment.
  27. if (deployment_dir.exists)
  28. {
  29. foreach (entry; dirEntries(deployment_dir, "*", SpanMode.depth))
  30. {
  31. if (entry.isDir)
  32. entry.rmdir;
  33. else
  34. {
  35. entry.makeWritable;
  36. entry.remove;
  37. }
  38. }
  39. deployment_dir.rmdir;
  40. }
  41. foreach (ref f; deployables)
  42. f.makeReadOnly;
  43.  
  44. // Execute test.
  45. const dub = environment.get("DUB", buildPath(__FILE_FULL_PATH__.dirName.dirName, "bin", "dub.exe"));
  46. const cmd = [dub, "build", "--build=release"];
  47. const result = execute(cmd, null, Config.none, size_t.max, project_dir);
  48. if (result.status || result.output.canFind("Failed"))
  49. {
  50. writefln("\n> %-(%s %)", cmd);
  51. writeln("===========================================================");
  52. writeln(result.output);
  53. writeln("===========================================================");
  54. writeln("Last command failed with exit code ", result.status, '\n');
  55. return 1;
  56. }
  57.  
  58. foreach (deployed; dirEntries(deployment_dir, "*", SpanMode.depth).filter!isFile)
  59. if (!isWritable(deployed))
  60. {
  61. writeln(deployed, " is expected to be writable, but it is not.");
  62. return 1;
  63. }
  64.  
  65. return 0;
  66. }
  67.  
  68. void makeReadOnly(string name)
  69. {
  70. version (Windows)
  71. {
  72. import core.sys.windows.windows;
  73.  
  74. name.setAttributes(name.getAttributes() | FILE_ATTRIBUTE_READONLY);
  75. }
  76. else version (Posix)
  77. {
  78. import core.sys.posix.sys.stat;
  79.  
  80. name.setAttributes(name.getAttributes() & ~(S_IWUSR | S_IWGRP | S_IWOTH));
  81. }
  82. else
  83. static assert("Needs implementation.");
  84.  
  85. import std.exception;
  86. import std.stdio;
  87. assertThrown!ErrnoException(File(name, "w"));
  88. }
  89.  
  90. void makeWritable(string name)
  91. {
  92. version (Windows)
  93. {
  94. import core.sys.windows.windows;
  95.  
  96. name.setAttributes(name.getAttributes() & ~FILE_ATTRIBUTE_READONLY);
  97. }
  98. else version (Posix)
  99. {
  100. import core.sys.posix.sys.stat;
  101.  
  102. name.setAttributes(name.getAttributes() | S_IWUSR);
  103. }
  104. else
  105. static assert("Needs implementation.");
  106.  
  107. import std.exception;
  108. import std.stdio;
  109. assertNotThrown!ErrnoException(File(name, "w"));
  110. }
  111.  
  112. bool isWritable(string name)
  113. {
  114. version (Windows)
  115. {
  116. import core.sys.windows.windows;
  117.  
  118. return (name.getAttributes() & FILE_ATTRIBUTE_READONLY) == 0;
  119. }
  120. else version (Posix)
  121. {
  122. import core.sys.posix.sys.stat;
  123.  
  124. return (name.getAttributes() & S_IWUSR) != 0;
  125. }
  126. else
  127. static assert("Needs implementation.");
  128. }