FileMode.java
package network.ike.plugin.scaffold;
import java.nio.file.attribute.PosixFilePermission;
import java.util.EnumSet;
import java.util.Set;
/**
* Filesystem mode a scaffold-written file should carry on disk.
*
* <p>Declared per manifest entry via the optional {@code mode} key and
* applied by {@link ScaffoldApplier} on POSIX filesystems. Three named
* modes cover every scaffold file the manifest ships:
*
* <ul>
* <li>{@link #DEFAULT} (0644) — ordinary tracked / tool-owned files;
* the implicit mode when {@code mode} is absent.</li>
* <li>{@link #EXECUTABLE} (0755) — scripts that must run, e.g.
* {@code mvnw}. Without this the applier would publish them
* non-executable (every write goes through a 0600 temp file) and
* {@code ./mvnw} would fail.</li>
* <li>{@link #PRIVATE} (0600) — owner-only, intentionally
* non-executable files, e.g. the parked VCS-bridge git hooks.</li>
* </ul>
*
* <p>The string values are the {@code mode:} tokens authors write in
* {@code scaffold-manifest.yaml}; {@link #fromManifest(Object)} parses
* them once at apply time, turning the YAML string into this enum so
* the rest of the applier reasons over a type rather than a raw mode.
*/
public enum FileMode {
/** 0644 — owner read/write, group/other read. The implicit default. */
DEFAULT("default", 0644),
/** 0755 — adds the executable bit for all; for runnable scripts. */
EXECUTABLE("executable", 0755),
/** 0600 — owner read/write only; non-executable and owner-private. */
PRIVATE("private", 0600);
private final String manifestValue;
private final int octal;
FileMode(String manifestValue, int octal) {
this.manifestValue = manifestValue;
this.octal = octal;
}
/**
* The token used in a manifest entry's {@code mode} field.
*
* @return the lowercase manifest token (e.g. {@code "executable"})
*/
public String manifestValue() {
return manifestValue;
}
/**
* The POSIX mode bits this mode maps to.
*
* @return octal permission bits (e.g. {@code 0755})
*/
public int octal() {
return octal;
}
/**
* Whether this mode was explicitly requested (anything other than
* {@link #DEFAULT}). Explicit modes are enforced on every write;
* {@code DEFAULT} preserves a pre-existing file's permissions on
* update so the applier never loosens, say, a locked-down
* {@code ~/.m2/settings.xml}.
*
* @return {@code true} for {@link #EXECUTABLE} and {@link #PRIVATE}
*/
public boolean isExplicit() {
return this != DEFAULT;
}
/**
* Resolve a manifest {@code mode} value to a {@link FileMode}.
*
* @param raw the raw YAML value of the entry's {@code mode} key;
* {@code null} or blank yields {@link #DEFAULT}
* @return the matching mode
* @throws ScaffoldException if {@code raw} is a non-blank value that
* names no known mode
*/
public static FileMode fromManifest(Object raw) {
if (raw == null) {
return DEFAULT;
}
String token = raw.toString().trim();
if (token.isEmpty()) {
return DEFAULT;
}
for (FileMode mode : values()) {
if (mode.manifestValue.equalsIgnoreCase(token)) {
return mode;
}
}
throw new ScaffoldException(
"unknown file mode '" + token
+ "' (expected one of: default, executable, "
+ "private)");
}
/**
* Expand this mode's octal bits into a {@link PosixFilePermission}
* set suitable for {@link java.nio.file.Files#setPosixFilePermissions}.
*
* @return a fresh, mutable permission set
*/
public Set<PosixFilePermission> toPosixPermissions() {
Set<PosixFilePermission> perms =
EnumSet.noneOf(PosixFilePermission.class);
if ((octal & 0400) != 0) perms.add(PosixFilePermission.OWNER_READ);
if ((octal & 0200) != 0) perms.add(PosixFilePermission.OWNER_WRITE);
if ((octal & 0100) != 0) perms.add(PosixFilePermission.OWNER_EXECUTE);
if ((octal & 0040) != 0) perms.add(PosixFilePermission.GROUP_READ);
if ((octal & 0020) != 0) perms.add(PosixFilePermission.GROUP_WRITE);
if ((octal & 0010) != 0) perms.add(PosixFilePermission.GROUP_EXECUTE);
if ((octal & 0004) != 0) perms.add(PosixFilePermission.OTHERS_READ);
if ((octal & 0002) != 0) perms.add(PosixFilePermission.OTHERS_WRITE);
if ((octal & 0001) != 0) perms.add(PosixFilePermission.OTHERS_EXECUTE);
return perms;
}
}