/+ dub.json: {
"name": "issue2234_copy_read_only_files"
} +/
/*
When DUB copies read-only files to the targetPath, the read-only flag must be
removed. If not, any subsequent copy operations will fail.
Version control systems such as Git Large File Storage typically mark binary
files as read-only, to prevent simultaneous edits in unmergeable formats.
*/
module issue2234_copy_read_only_files.script;
import
std.algorithm.searching,
std.algorithm.iteration,
std.stdio, std.process, std.path, std.file;
int main()
{
const project_dir = buildPath(__FILE_FULL_PATH__.dirName, "issue2234-copy-read-only-files");
const deployment_dir = buildPath(project_dir, "bin");
auto deployables = dirEntries(buildPath(project_dir, "files"), "*", SpanMode.depth).filter!isFile;
// Prepare environment.
if (deployment_dir.exists)
{
foreach (entry; dirEntries(deployment_dir, "*", SpanMode.depth))
{
if (entry.isDir)
entry.rmdir;
else
{
entry.makeWritable;
entry.remove;
}
}
deployment_dir.rmdir;
}
foreach (ref f; deployables)
f.makeReadOnly;
// Execute test.
const dub = environment.get("DUB", buildPath(__FILE_FULL_PATH__.dirName.dirName, "bin", "dub.exe"));
const cmd = [dub, "build", "--build=release"];
const result = execute(cmd, null, Config.none, size_t.max, project_dir);
if (result.status || result.output.canFind("Failed"))
{
writefln("\n> %-(%s %)", cmd);
writeln("===========================================================");
writeln(result.output);
writeln("===========================================================");
writeln("Last command failed with exit code ", result.status, '\n');
return 1;
}
foreach (deployed; dirEntries(deployment_dir, "*", SpanMode.depth).filter!isFile)
if (!isWritable(deployed))
{
writeln(deployed, " is expected to be writable, but it is not.");
return 1;
}
return 0;
}
void makeReadOnly(string name)
{
version (Windows)
{
import core.sys.windows.windows;
name.setAttributes(name.getAttributes() | FILE_ATTRIBUTE_READONLY);
}
else version (Posix)
{
import core.sys.posix.sys.stat;
name.setAttributes(name.getAttributes() & ~(S_IWUSR | S_IWGRP | S_IWOTH));
}
else
static assert("Needs implementation.");
import std.exception;
import std.stdio;
assertThrown!ErrnoException(File(name, "w"));
}
void makeWritable(string name)
{
version (Windows)
{
import core.sys.windows.windows;
name.setAttributes(name.getAttributes() & ~FILE_ATTRIBUTE_READONLY);
}
else version (Posix)
{
import core.sys.posix.sys.stat;
name.setAttributes(name.getAttributes() | S_IWUSR);
}
else
static assert("Needs implementation.");
import std.exception;
import std.stdio;
assertNotThrown!ErrnoException(File(name, "w"));
}
bool isWritable(string name)
{
version (Windows)
{
import core.sys.windows.windows;
return (name.getAttributes() & FILE_ATTRIBUTE_READONLY) == 0;
}
else version (Posix)
{
import core.sys.posix.sys.stat;
return (name.getAttributes() & S_IWUSR) != 0;
}
else
static assert("Needs implementation.");
}