Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BXC-4719 archive project #109

Merged
merged 9 commits into from
Sep 25, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package edu.unc.lib.boxc.migration.cdm;

import edu.unc.lib.boxc.migration.cdm.exceptions.InvalidProjectStateException;
import edu.unc.lib.boxc.migration.cdm.services.ArchiveProjectsService;
import org.slf4j.Logger;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParentCommand;
import picocli.CommandLine.Command;

import java.util.List;
import java.util.concurrent.Callable;

import static edu.unc.lib.boxc.migration.cdm.util.CLIConstants.outputLogger;
import static org.slf4j.LoggerFactory.getLogger;

@Command(name = "archive",
description = {"Archive a project or list of projects. These projects will be moved to an 'archived' folder."})
public class ArchiveProjectsCommand implements Callable<Integer> {
private static final Logger log = getLogger(ArchiveProjectsCommand.class);

@ParentCommand
private CLIMain parentCommand;

@Option(names = { "-p", "--project-names" },
split = ",",
description = {"Specify project or list of projects to be archived"})
private List<String> projectNames;

private ArchiveProjectsService archiveProjectsService;

@Override
public Integer call() throws Exception {
try {
archiveProjectsService = new ArchiveProjectsService();
archiveProjectsService.archiveProjects(parentCommand.getWorkingDirectory(), projectNames);
return 0;
} catch(InvalidProjectStateException e) {
outputLogger.info("Archiving project(s) failed: {}", e.getMessage());
return 1;
} catch (Exception e) {
log.error("Failed to archive project(s)", e);
outputLogger.info("Archiving project(s) failed: {}", e.getMessage());
return 1;
}
}
}
3 changes: 2 additions & 1 deletion src/main/java/edu/unc/lib/boxc/migration/cdm/CLIMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
AggregateFilesCommand.class,
PermissionsCommand.class,
ExportObjectsCommand.class,
ListProjectsCommand.class
ListProjectsCommand.class,
ArchiveProjectsCommand.class
})
public class CLIMain implements Callable<Integer> {
@Option(names = { "-w", "--work-dir" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import edu.unc.lib.boxc.migration.cdm.services.ProjectPropertiesService;
import edu.unc.lib.boxc.migration.cdm.services.SourceFileService;
import org.slf4j.Logger;
import picocli.CommandLine.Option;
import picocli.CommandLine.Command;
import picocli.CommandLine.ParentCommand;

Expand All @@ -29,6 +30,10 @@ public class ListProjectsCommand implements Callable<Integer> {
@ParentCommand
private CLIMain parentCommand;

@Option(names = { "-ia", "--include-archived" },
description = "Include archived projects in list of chompb projects")
private boolean includeArchived;

private CdmFieldService fieldService;
private CdmIndexService indexService;
private ProjectPropertiesService propertiesService;
Expand All @@ -40,7 +45,7 @@ public Integer call() {
try {
initialize();
ObjectMapper mapper = new ObjectMapper();
JsonNode listProjects = listProjectsService.listProjects(parentCommand.getWorkingDirectory());
JsonNode listProjects = listProjectsService.listProjects(parentCommand.getWorkingDirectory(), includeArchived);
String prettyPrintList = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(listProjects);
outputLogger.info(prettyPrintList);
return 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package edu.unc.lib.boxc.migration.cdm.services;

import edu.unc.lib.boxc.migration.cdm.exceptions.InvalidProjectStateException;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

/**
* Service for archiving chompb project(s)
* @author krwong
*/
public class ArchiveProjectsService {
private static final Logger log = LoggerFactory.getLogger(ArchiveProjectsService.class);
public static final String ARCHIVED = ".archived";

/**
* Archive a list of projects
*/
public void archiveProjects(Path currentDirectory, List<String> projectNames) throws IOException {
if (projectNames == null || projectNames.isEmpty()) {
throw new InvalidProjectStateException("Project names cannot be empty. " +
"Please specify a valid project name(s).");
}

Path archiveDirectory = currentDirectory.resolve(ARCHIVED);
for (String projectName : projectNames) {
Path projectDirectory = currentDirectory.resolve(projectName);

if (Files.notExists(projectDirectory)) {
throw new InvalidProjectStateException("Migration project " + projectName + " does not exist");
}

if (Files.isDirectory(projectDirectory)) {
FileUtils.moveDirectoryToDirectory(projectDirectory.toFile(),
archiveDirectory.toFile(), true);
} else {
throw new InvalidProjectStateException("Migration project " + projectName + " is not a directory");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public class ListProjectsService {
* List projects in given directory
* @return jsonNode of projects
*/
public JsonNode listProjects(Path directory) throws Exception {
public JsonNode listProjects(Path directory, boolean includeArchived) throws Exception {
if (Files.notExists(directory)) {
throw new InvalidProjectStateException("Path " + directory + " does not exist");
}
Expand All @@ -55,14 +55,30 @@ public JsonNode listProjects(Path directory) throws Exception {
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
ArrayNode arrayNode = mapper.createArrayNode();

// list projects
listProjectsInDirectory(directory, mapper, arrayNode);

// list archived projects
if (includeArchived) {
listProjectsInDirectory(directory.resolve(ArchiveProjectsService.ARCHIVED), mapper, arrayNode);
}

log.debug(arrayNode.toString());
return arrayNode;
}

private void listProjectsInDirectory(Path directory, ObjectMapper mapper, ArrayNode arrayNode) throws Exception {
for (File file : directory.toFile().listFiles()) {
if (file.isDirectory()) {
try {
MigrationProject project = initializeProject(file.toPath());

Path projectPath = file.toPath().toAbsolutePath();
String projectStatus = status(project);
ArrayNode allowedActions = mapper.valueToTree(allowedActions(project));
ArrayNode allowedActions = mapper.createArrayNode();
if (!projectStatus.equals("archived")) {
allowedActions = mapper.valueToTree(allowedActions(project));
}
JsonNode projectProperties = mapper.readTree(project.getProjectPropertiesPath().toFile());

// add project info to JSON
Expand All @@ -77,9 +93,6 @@ public JsonNode listProjects(Path directory) throws Exception {
}
}
}
log.debug(arrayNode.toString());

return arrayNode;
}

/**
Expand All @@ -90,11 +103,9 @@ public JsonNode listProjects(Path directory) throws Exception {
private String status(MigrationProject project) {
String status = null;

// TODO: add archived state
// if () {
// status = "archived";
// }
if (!project.getProjectProperties().getSipsSubmitted().isEmpty()) {
if (project.getProjectPath().toString().contains("/" + ArchiveProjectsService.ARCHIVED + "/")) {
status = "archived";
} else if (!project.getProjectProperties().getSipsSubmitted().isEmpty()) {
status = "ingested";
} else if (project.getProjectProperties().getSipsGeneratedDate() != null) {
status = "sips_generated";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package edu.unc.lib.boxc.migration.cdm;

import edu.unc.lib.boxc.migration.cdm.services.ArchiveProjectsService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.nio.file.Files;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class ArchiveProjectsCommandIT extends AbstractCommandIT {
private static final String PROJECT_NAME_2 = "proj2";

@BeforeEach
public void setup() throws Exception {
initProjectAndHelper();
setupChompbConfig();
}

@Test
public void archiveProjectTest() throws Exception {
String[] args = new String[] {
"-w", String.valueOf(baseDir),
"archive",
"-p", project.getProjectName()};
executeExpectSuccess(args);

assertTrue(Files.exists(tmpFolder.resolve(ArchiveProjectsService.ARCHIVED + "/"
+ project.getProjectName())));
}

@Test
public void archiveInvalidProjectTest() throws Exception {
String[] args = new String[] {
"-w", String.valueOf(baseDir),
"archive",
"-p", PROJECT_NAME_2};
executeExpectFailure(args);

assertOutputContains("Migration project " + PROJECT_NAME_2 + " does not exist");
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package edu.unc.lib.boxc.migration.cdm;

import edu.unc.lib.boxc.migration.cdm.model.MigrationProject;
import edu.unc.lib.boxc.migration.cdm.services.ArchiveProjectsService;
import edu.unc.lib.boxc.migration.cdm.services.ListProjectsService;
import edu.unc.lib.boxc.migration.cdm.services.MigrationProjectFactory;
import edu.unc.lib.boxc.migration.cdm.test.BxcEnvironmentHelper;
Expand All @@ -9,6 +10,7 @@
import org.junit.jupiter.api.Test;

import java.nio.file.Path;
import java.util.Collections;

public class ListProjectsCommandIT extends AbstractCommandIT {
private static final String PROJECT_ID_2 = "proj2";
Expand All @@ -30,7 +32,7 @@ public void invalidDirectoryTest() throws Exception {
}

@Test
public void listProjectsTest() throws Exception {
public void listProjectTest() throws Exception {
String[] args = new String[] {
"-w", String.valueOf(baseDir),
"list_projects" };
Expand All @@ -42,6 +44,24 @@ public void listProjectsTest() throws Exception {
assertOutputContains("\"name\" : \"" + PROJECT_ID + "\"");
}

@Test
public void listArchivedProjectTest() throws Exception {
ArchiveProjectsService archiveProjectsService = new ArchiveProjectsService();
archiveProjectsService.archiveProjects(tmpFolder, Collections.singletonList(PROJECT_ID));

String[] args = new String[] {
"-w", String.valueOf(baseDir),
"list_projects",
"--include-archived"};
executeExpectSuccess(args);

assertOutputContains("\"" + ListProjectsService.PROJECT_PATH + "\" : \""
+ baseDir.resolve(ArchiveProjectsService.ARCHIVED+ "/" + PROJECT_ID) + "\"");
assertOutputContains("\"" + ListProjectsService.STATUS + "\" : \"archived\"");
assertOutputContains("\"" + ListProjectsService.ALLOWED_ACTIONS + "\" : [ ]");
assertOutputContains("\"name\" : \"" + PROJECT_ID + "\"");
}

@Test
public void listMultipleProjectsTest() throws Exception {
project = MigrationProjectFactory.createMigrationProject(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package edu.unc.lib.boxc.migration.cdm.services;

import edu.unc.lib.boxc.migration.cdm.model.MigrationProject;
import edu.unc.lib.boxc.migration.cdm.test.BxcEnvironmentHelper;
import edu.unc.lib.boxc.migration.cdm.test.CdmEnvironmentHelper;
import edu.unc.lib.boxc.migration.cdm.test.SipServiceHelper;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.MockitoAnnotations.openMocks;

public class ArchiveProjectsServiceTest {
private static final String PROJECT_NAME = "proj";
private static final String PROJECT_NAME_2 = "proj2";

@TempDir
public Path tmpFolder;

private SipServiceHelper testHelper;
private MigrationProject project;
private ArchiveProjectsService service;

private AutoCloseable closeable;

@BeforeEach
public void setup() throws Exception {
closeable = openMocks(this);
project = MigrationProjectFactory.createMigrationProject(
tmpFolder, PROJECT_NAME, null, "user", CdmEnvironmentHelper.DEFAULT_ENV_ID,
BxcEnvironmentHelper.DEFAULT_ENV_ID, MigrationProject.PROJECT_SOURCE_CDM);
testHelper = new SipServiceHelper(project, tmpFolder);

service = new ArchiveProjectsService();
}

@AfterEach
void closeService() throws Exception {
closeable.close();
}

@Test
public void archiveProjectTest() throws Exception {
List<String> testProjects = new ArrayList<>();
testProjects.add(PROJECT_NAME);
service.archiveProjects(tmpFolder, testProjects);

assertTrue(Files.exists(tmpFolder.resolve(service.ARCHIVED + "/" + PROJECT_NAME)));
}

@Test
public void archiveInvalidProjectTest() throws Exception {
try {
List<String> testProjects = new ArrayList<>();
testProjects.add(PROJECT_NAME_2);
service.archiveProjects(tmpFolder, testProjects);
fail();
} catch (Exception e) {
assertTrue(e.getMessage().contains("Migration project " + PROJECT_NAME_2 + " does not exist"));
}
}

@Test
public void archiveEmptyProjectTest() throws Exception {
try {
List<String> testProjects = new ArrayList<>();;
service.archiveProjects(tmpFolder, testProjects);
fail();
} catch (Exception e) {
assertTrue(e.getMessage().contains("Project names cannot be empty"));
}
}

@Test
public void archiveMultipleProjectsTest() throws Exception {
project = MigrationProjectFactory.createMigrationProject(
tmpFolder, PROJECT_NAME_2, null, "user", CdmEnvironmentHelper.DEFAULT_ENV_ID,
BxcEnvironmentHelper.DEFAULT_ENV_ID, MigrationProject.PROJECT_SOURCE_CDM);

List<String> testProjects = new ArrayList<>();
testProjects.add(PROJECT_NAME);
testProjects.add(PROJECT_NAME_2);
service.archiveProjects(tmpFolder, testProjects);

assertTrue(Files.exists(tmpFolder.resolve(service.ARCHIVED + "/" + PROJECT_NAME)));
assertTrue(Files.exists(tmpFolder.resolve(service.ARCHIVED + "/" + PROJECT_NAME_2)));
}
}
Loading
Loading