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

fix(CLI) WatchMode Fix Refs: #28593 #29067

Merged
merged 15 commits into from
Jul 4, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

import static com.dotcms.common.LocationUtils.encodePath;
import static com.dotcms.model.config.Workspace.FILES_NAMESPACE;
import static com.dotcms.common.WorkspaceManager.resolvePath;

import com.dotcms.model.asset.AbstractAssetSync.PushType;
import com.dotcms.model.asset.AssetSync;
import com.dotcms.model.asset.AssetView;
import com.dotcms.model.asset.FolderSync;
import com.dotcms.model.asset.FolderView;
import com.google.common.base.Function;
import com.google.common.base.Strings;
import java.util.Map;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
Expand Down Expand Up @@ -174,16 +177,16 @@ public static RemotePathStructure parseRemotePath(String remotePathToParse) {
* Parses the root paths based on the workspace and source files.
*
* @param workspace the workspace directory
* @param source the source file or directory
* @param source the source file or directory within the workspace to parse
* @return a list of root paths
* @throws IllegalArgumentException if the source path is outside the workspace or does not follow the required
* structure
*/
public static List<String> parseRootPaths(File workspace, File source) {

var sourcePath = source.toPath();
var workspacePath = workspace.toPath();
public static List<String> parseRootPaths(final File workspace, final File source) {

//Call resolve Path to get an absolute path
var sourcePath = resolvePath(source.toPath());
var workspacePath = workspace.toPath().toAbsolutePath().normalize();
var workspaceCount = workspacePath.getNameCount();
var sourceCount = sourcePath.getNameCount();

Expand All @@ -193,45 +196,58 @@ public static List<String> parseRootPaths(File workspace, File source) {

// Check if we are inside the workspace but also inside the files folder
if (sourceCount > workspaceCount + 1) {
if (!source.getAbsolutePath().startsWith(
workspace.getAbsolutePath() + File.separator + FILES_NAMESPACE + File.separator
)) {
throw new IllegalArgumentException("Invalid source path. Source path must be inside the files folder or " +
"at the root of the workspace");
final Path files = Path.of(workspace.getAbsolutePath(), FILES_NAMESPACE)
.toAbsolutePath().normalize();
if (!sourcePath.startsWith(files)) {
throw new IllegalArgumentException(
String.format(
"Invalid source path [%s]. Source path must be inside the files folder or "
+
"at the root of the workspace [%s] ", sourcePath,
workspacePath));
}
} else if (sourceCount == workspaceCount + 1) {
if (!source.getName().equals(FILES_NAMESPACE)) {
throw new IllegalArgumentException("Invalid source path. Source path must be inside the files folder or " +
"at the root of the workspace");
final Path files = Path.of(FILES_NAMESPACE).toAbsolutePath().normalize();
if (!sourcePath.startsWith(files)) {
throw new IllegalArgumentException(
"Invalid source path. Source path must be inside the files folder or " +
"at the root of the workspace");
}
}

return parseRootPaths(sourcePath, workspaceCount, sourceCount);
}

/**
* Parses the root paths based on the workspace and source paths.
* @param sourcePath the source path
* @param workspaceCount the workspace path components count
* @param sourceCount the source path components count
* @return a list of root paths
*/
private static List<String> parseRootPaths(final Path sourcePath, final int workspaceCount,
final int sourceCount) {
var rootPaths = new ArrayList<String>();

if (workspaceCount == sourceCount) {// We are at the root of the workspace
if (source.exists()) {
rootPaths.addAll(fromRootFolder(source));
}
} else if (workspaceCount + 1 == sourceCount) {// We should be at the files level
if (source.exists()) {
rootPaths.addAll(fromFilesFolder(source));
}
} else if (workspaceCount + 2 == sourceCount) {// We should be at the status level
if (source.exists()) {
rootPaths.addAll(fromStatusFolder(source));
}
} else if (workspaceCount + 3 == sourceCount) {// We should be at the language level
if (source.exists()) {
rootPaths.addAll(fromLanguageFolder(source));
}
} else if (workspaceCount + 4 == sourceCount) {// We should be at the site level
if (source.exists()) {
rootPaths.add(fromSiteFolder(source));
}
} else {
rootPaths.add(source.getAbsolutePath());
final File sourcePathFile = sourcePath.toFile();

if (!sourcePathFile.exists()) {
return rootPaths;
}

Map<Integer, Function<File, List<String>>> levelFunctions = Map.of(
workspaceCount, AssetsUtils::fromRootFolder,
workspaceCount + 1, AssetsUtils::fromFilesFolder,
workspaceCount + 2, AssetsUtils::fromStatusFolder,
workspaceCount + 3, AssetsUtils::fromLanguageFolder,
workspaceCount + 4, AssetsUtils::fromSiteFolder
);

if (levelFunctions.containsKey(sourceCount)) {
rootPaths.addAll(levelFunctions.get(sourceCount).apply(sourcePathFile));
} else {
rootPaths.add(sourcePathFile.getAbsolutePath());
}
return rootPaths;
}

Expand Down Expand Up @@ -318,7 +334,7 @@ private static List<String> fromLanguageFolder(File languageFolder) {
}

// This is our root path to analyze
rootPaths.add(fromSiteFolder(siteFolder));
rootPaths.addAll(fromSiteFolder(siteFolder));
}
}

Expand All @@ -331,8 +347,8 @@ private static List<String> fromLanguageFolder(File languageFolder) {
* @param siteFolder the site folder
* @return the root path
*/
private static String fromSiteFolder(File siteFolder) {
return siteFolder.getAbsolutePath();
private static List<String> fromSiteFolder(File siteFolder) {
return List.of(siteFolder.getAbsolutePath());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.dotcms.model.config.Workspace;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;

/**
Expand Down Expand Up @@ -41,4 +42,21 @@ public interface WorkspaceManager {
*/
void destroy(final Workspace workspace) throws IOException;

/**
* Resolves the path.
* @param inputPath the input path
* @return the resolved path
*/
static Path resolvePath(final Path inputPath) {

// if the input path is not absolute, resolve it against the current directory
if (!inputPath.isAbsolute()) {
// Get the current directory
final Path currentDir = Paths.get("").toAbsolutePath().normalize();
return currentDir.resolve(inputPath).normalize();
}
// otherwise, return the normalized input path
return inputPath.normalize();
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.dotcms.common;

import static com.dotcms.common.WorkspaceManager.*;

import com.dotcms.api.provider.YAMLMapperSupplier;
import com.dotcms.model.config.Workspace;
import com.dotcms.model.config.WorkspaceInfo;
Expand Down Expand Up @@ -129,7 +131,17 @@ public Workspace getOrCreate(final Path currentPath, final boolean findWorkspace
}

public Optional<Workspace> findWorkspace(Path currentPath) {
final Optional<Path> projectRoot = findProjectRoot(currentPath);
// Resolve the path as it may be relative
final Path resolvedPath = resolvePath(currentPath);
logger.debugf("currentPath = %s", resolvedPath);

final File file = resolvedPath.toFile();
if (!file.exists()) {
throw new IllegalArgumentException(
String.format("Path [%s] does not exist", resolvedPath)
);
}
final Optional<Path> projectRoot = findProjectRoot(resolvedPath);
return projectRoot.map(this::workspace);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.dotcms.cli.common.PushMixin;
import com.dotcms.common.WorkspaceManager;
import com.dotcms.model.config.Workspace;
import java.io.File;
import java.nio.file.Path;
import java.util.Optional;

Expand Down Expand Up @@ -55,15 +56,22 @@ default boolean isGlobalPush() {
WorkspaceManager workspaceManager();

default Optional<Workspace> workspace(){
return workspaceManager().findWorkspace(getPushMixin().path());
final Path path = getPushMixin().path();
final WorkspaceManager workspaceManager = workspaceManager();
// This should only really concern Integration tests.
// Workspace param is hidden we only use for testing in the Push commands
final File workspace = getPushMixin().workspace;

//If No explicit workspace is provided, we rely on the path to find the workspace
return workspaceManager.findWorkspace( workspace != null ? workspace.toPath() : path);
}

default Path workingRootDir() {
final Optional<Workspace> workspace = workspace();
if (workspace.isPresent()) {
return workspace.get().root();
}
throw new IllegalArgumentException("No valid workspace found.");
return getPushMixin().path();
jgambarios marked this conversation as resolved.
Show resolved Hide resolved
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public Integer call() throws Exception {
}

File inputFile = this.getPushMixin().path().toFile();
if (!inputFile.isAbsolute()) {
if (!inputFile.isAbsolute() && inputFile.isFile()) {
inputFile = Path.of(workspace.get().contentTypes().toString(), inputFile.getName())
.toFile();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ private Pair<Workspace, File> resolveWorkspaceAndPath() throws IOException {
}

File inputFile = this.getPushMixin().path().toFile();
if (!inputFile.isAbsolute()) {
if (!inputFile.isAbsolute() && inputFile.isFile()) {
jgambarios marked this conversation as resolved.
Show resolved Hide resolved
// If the path is not absolute, we assume it is relative to the files folder
inputFile = Path.of(
workspace.get().files().toString(), inputFile.getPath()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public Integer call() throws Exception {
}

File inputFile = this.getPushMixin().path().toFile();
if (!inputFile.isAbsolute()) {
if (!inputFile.isAbsolute() && inputFile.isFile() ) {
inputFile = Path.of(workspace.get().languages().toString(), inputFile.getName())
.toFile();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ private int push() throws Exception {
}

File inputFile = this.getPushMixin().path().toFile();
if (!inputFile.isAbsolute()) {
if (!inputFile.isAbsolute() && inputFile.isFile()) {
inputFile = Path.of(workspace.get().sites().toString(), inputFile.getName())
.toFile();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,12 @@ private static void incCallDepth() {
}

int handleWatchPush(final IExecutionStrategy underlyingStrategy, final ParseResult parseResult, final DotPush push) {
final PushMixin pushMixin = push.getPushMixin();
push.getOutput().println("Running in Watch Mode on " + push.workingRootDir());

final Path watchedPath = watchedPath(push);
push.getOutput().println("Running in Watch Mode on " + watchedPath);
try {
return watch(underlyingStrategy, parseResult, push.workingRootDir(), pushMixin.interval);
final PushMixin pushMixin = push.getPushMixin();
return watch(underlyingStrategy, parseResult, watchedPath, pushMixin.interval);
} catch (IOException e) {
throw new ExecutionException(parseResult.commandSpec().commandLine(), "Failure starting watch service", e);
} catch (InterruptedException e) {
Expand All @@ -227,6 +229,19 @@ int handleWatchPush(final IExecutionStrategy underlyingStrategy, final ParseResu
}
}

/**
* Returns the path to watch for the given push command.
* @param push the push command
* @return the path to watch
*/
private Path watchedPath(final DotPush push) {
final PushMixin pushMixin = push.getPushMixin();
if (pushMixin.isUserProvidedPath()) {
return pushMixin.path();
}
return push.workingRootDir();
}

private int watch(final IExecutionStrategy underlyingStrategy, final ParseResult parseResult,
final Path workingDir, final int interval) throws IOException, InterruptedException {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ public class PushMixin {
description = "local directory or file to push")
public File pushPath;

// Workspace is hidden because it is not used in the push command.
// We already have a pushPath parameter to specify the path to push.
// This is here for testing purposes.
// We're not using here our WorkspaceMixin because this param is meant to be hidden.
@CommandLine.Option(names = {"--workspace"},
hidden = true,
description = {"The workspace directory.",
"Current directory is used if not specified"})
public File workspace;

@CommandLine.Option(names = {"--dry-run"}, defaultValue = "false",
description = {
"When this option is enabled, the push process displays information about the changes that would be made on ",
Expand Down Expand Up @@ -69,12 +79,25 @@ public class PushMixin {
* @return The path of the file.
*/
public Path path() {
final Path workingDir = (this.workspace != null ? this.workspace.toPath() : Path.of("")).normalize().toAbsolutePath();
if (null == pushPath) {
return Path.of("").toAbsolutePath();
return workingDir;
}
return pushPath.toPath().normalize().toAbsolutePath();
return workingDir.resolve(pushPath.toPath()).normalize().toAbsolutePath();
}

/**
* Returns whether a path is provided.
* @return true if a path is provided; false otherwise.
*/
public boolean isUserProvidedPath(){
return null != pushPath;
}

/**
* Returns whether the watch mode is enabled.
* @return true if the watch mode is enabled; false otherwise.
*/
public boolean isWatchMode(){
return null != interval;
}
Expand Down
Loading
Loading