mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-10-26 08:06:09 +01:00
Keep file attributes on modification
This commit is contained in:
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Fixed
|
||||
- Modification for mercurial repositories with enabled XSRF protection
|
||||
- Does not throw NullPointerException when merge fails without normal merge conflicts
|
||||
- Keep file attributes on modification
|
||||
|
||||
### Removed
|
||||
- Enunciate rest documentation
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.repository.Repository;
|
||||
|
||||
@@ -10,8 +12,13 @@ import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
|
||||
import static java.util.Optional.empty;
|
||||
import static java.util.Optional.of;
|
||||
import static sonia.scm.AlreadyExistsException.alreadyExists;
|
||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||
import static sonia.scm.NotFoundException.notFound;
|
||||
@@ -22,6 +29,8 @@ import static sonia.scm.NotFoundException.notFound;
|
||||
*/
|
||||
public interface ModifyWorkerHelper extends ModifyCommand.Worker {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(ModifyWorkerHelper.class);
|
||||
|
||||
@Override
|
||||
default void delete(String toBeDeleted) throws IOException {
|
||||
Path fileToBeDeleted = new File(getWorkDir(), toBeDeleted).toPath();
|
||||
@@ -57,10 +66,34 @@ public interface ModifyWorkerHelper extends ModifyCommand.Worker {
|
||||
if (!targetFile.toFile().exists()) {
|
||||
throw notFound(createFileContext(path));
|
||||
}
|
||||
Optional<Set<PosixFilePermission>> posixFilePermissions = getPosixFilePermissions(targetFile);
|
||||
Files.move(file.toPath(), targetFile, REPLACE_EXISTING);
|
||||
posixFilePermissions.ifPresent(permissions -> setPosixFilePermissions(targetFile, permissions));
|
||||
addFileToScm(path, targetFile);
|
||||
}
|
||||
|
||||
default Optional<Set<PosixFilePermission>> getPosixFilePermissions(Path targetFile) {
|
||||
try {
|
||||
return of(Files.getPosixFilePermissions(targetFile));
|
||||
} catch (UnsupportedOperationException e) {
|
||||
LOG.trace("posix file permissions not supported");
|
||||
return empty();
|
||||
} catch (IOException e) {
|
||||
LOG.info("could not read posix file permissions for file {}", targetFile);
|
||||
return empty();
|
||||
}
|
||||
}
|
||||
|
||||
default void setPosixFilePermissions(Path targetFile, Set<PosixFilePermission> permissions) {
|
||||
try {
|
||||
Files.setPosixFilePermissions(targetFile, permissions);
|
||||
} catch (UnsupportedOperationException e) {
|
||||
LOG.trace("posix file permissions not supported");
|
||||
} catch (IOException e) {
|
||||
LOG.info("could not write posix file permissions to file {}", targetFile);
|
||||
}
|
||||
}
|
||||
|
||||
void addFileToScm(String name, Path file);
|
||||
|
||||
default ContextEntry.ContextBuilder createFileContext(String path) {
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.Assumptions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junitpioneer.jupiter.TempDirectory;
|
||||
import sonia.scm.repository.Repository;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static java.nio.file.attribute.PosixFilePermission.GROUP_EXECUTE;
|
||||
import static java.nio.file.attribute.PosixFilePermission.GROUP_READ;
|
||||
import static java.nio.file.attribute.PosixFilePermission.OTHERS_EXECUTE;
|
||||
import static java.nio.file.attribute.PosixFilePermission.OTHERS_READ;
|
||||
import static java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE;
|
||||
import static java.nio.file.attribute.PosixFilePermission.OWNER_READ;
|
||||
import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@ExtendWith(TempDirectory.class)
|
||||
class ModifyWorkerHelperTest {
|
||||
|
||||
@Test
|
||||
void shouldKeepExecutableFlag(@TempDirectory.TempDir Path temp) throws IOException {
|
||||
|
||||
File target = createFile(temp, "executable.sh");
|
||||
File newFile = createFile(temp, "other");
|
||||
|
||||
Assumptions.assumeThatThrownBy(() -> {
|
||||
Files.setPosixFilePermissions(target.toPath(),
|
||||
ImmutableSet.of(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ, GROUP_EXECUTE, OTHERS_READ, OTHERS_EXECUTE));
|
||||
Files.setPosixFilePermissions(newFile.toPath(),
|
||||
ImmutableSet.of(OWNER_READ, OWNER_WRITE, GROUP_READ, OTHERS_READ));
|
||||
}).doesNotThrowAnyException(); // ignore this test on systems that does not support posix file permissions
|
||||
|
||||
ModifyWorkerHelper helper = new MinimalModifyWorkerHelper(temp);
|
||||
|
||||
helper.modify("executable.sh", newFile);
|
||||
|
||||
assertThat(Files.getPosixFilePermissions(target.toPath()))
|
||||
.contains(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ, GROUP_EXECUTE, OTHERS_READ, OTHERS_EXECUTE);
|
||||
}
|
||||
|
||||
private File createFile(Path temp, String fileName) throws IOException {
|
||||
File file = new File(temp.toFile(), fileName);
|
||||
FileWriter source = new FileWriter(file);
|
||||
source.write("something");
|
||||
source.close();
|
||||
return file;
|
||||
}
|
||||
|
||||
private static class MinimalModifyWorkerHelper implements ModifyWorkerHelper {
|
||||
|
||||
private final Path temp;
|
||||
|
||||
public MinimalModifyWorkerHelper(Path temp) {
|
||||
this.temp = temp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doScmDelete(String toBeDeleted) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFileToScm(String name, Path file) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getWorkDir() {
|
||||
return temp.toFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Repository getRepository() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBranch() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user