Skip to content

Commit 4aa9ae0

Browse files
Merge pull request #128 from wttech/repo-move
Repo copy/move/rename
2 parents c6de2d8 + c2d1fdc commit 4aa9ae0

File tree

13 files changed

+320
-53
lines changed

13 files changed

+320
-53
lines changed

README.md

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ It works seamlessly across AEM on-premise, AMS, and AEMaaCS environments.
4444
- [Minimal Example](#minimal-example)
4545
- [Arguments Example](#arguments-example)
4646
- [ACL Example](#acl-example)
47+
- [Repo Example](#repo-example)
4748
- [History](#history)
4849
- [Extension Scripts](#extension-scripts)
4950
- [Snippets](#snippets)
@@ -243,7 +244,7 @@ Be inspired by reviewing examples like [page thumbnail script](https://github.co
243244

244245
#### ACL example
245246

246-
The following example demonstrates how to create a user and a group, assign permissions, and add members to the group.
247+
The following example demonstrates how to create a user and a group, assign permissions, and add members to the group using the [ACL service](https://github.com/wttech/acm/blob/main/core/src/main/java/dev/vml/es/acm/core/acl/Acl.java) (`acl`).
247248

248249
```groovy
249250
boolean canRun() {
@@ -282,6 +283,58 @@ Logging is very descriptive allowing you to see what was done and what was skipp
282283

283284
<img src="docs/screenshot-content-script-acl-output.png" width="720" alt="ACM ACL Script Output">
284285

286+
#### Repo example
287+
288+
You can leverage the [repository service](https://github.com/wttech/acm/blob/main/core/src/main/java/dev/vml/es/acm/core/repo/Repo.java) (repo) to efficiently perform JCR operations such as reading, writing, and deleting nodes with concise, expressive code.
289+
The out-of-the-box AEM API often requires extensive boilerplate code and can behave unpredictably in certain scenarios. The [RepoResource](https://github.com/wttech/acm/blob/main/core/src/main/java/dev/vml/es/acm/core/repo/RepoResource.java) API streamlines these operations, making repository programming more enjoyable, concise, and reliable.
290+
291+
The repo service abstracts away the complexity of managing dry-run and auto-commit behaviors—features that are often error-prone and cumbersome to implement manually—ensuring safe, predictable, and streamlined repository operations.
292+
293+
```groovy
294+
void describeRun() {
295+
arguments.bool("dryRun") { value = true; switcher(); description = "Do not commit changes to the repository" }
296+
arguments.bool("clean") { value = true; switcher(); description = "Finally delete all created resources" }
297+
}
298+
299+
boolean canRun() {
300+
return condition.idleSelf()
301+
}
302+
303+
void doRun() {
304+
out.fromLogs()
305+
306+
repo.dryRun(arguments.value("dryRun")) {
307+
println "Creating a folder structure in the temporary directory of the repository."
308+
def dataFolder = repo.get("/tmp/acm/demo/data").ensureFolder()
309+
for (int i = 0; i < 5; i++) {
310+
def child = dataFolder.child("child-\${i+1}")
311+
child.save(["foo": "bar"])
312+
child.updateProperty("foo") { v -> v.toUpperCase() }
313+
}
314+
println "Folder '${dataFolder.path}' has now ${dataFolder.descendants().count()} descendant(s)."
315+
316+
println "Creating a post in the temporary directory of the repository."
317+
def postFolder = repo.get("/tmp/acm/demo/posts").ensureFolder()
318+
def post = postFolder.child("hello-world.yml")
319+
post.saveFile("application/x-yaml") { output ->
320+
formatter.yml.write(output, [
321+
title: "Hello World",
322+
description: "This is a sample post.",
323+
tags: ["sample", "post"]
324+
])
325+
}
326+
println "Post '${post.path}' has been created at ${post.property("jcr:created", java.time.LocalDateTime)}"
327+
328+
if (arguments.value("clean")) {
329+
dataFolder.delete()
330+
postFolder.delete()
331+
}
332+
}
333+
}
334+
```
335+
336+
<img src="docs/screenshot-content-script-repo-output.png" width="720" alt="ACM ACL Repo Output">
337+
285338
### History
286339

287340
All code executions are logged in the history. You can see the status of each execution, including whether it was successful or failed. The history also provides detailed logs for each execution, including any errors that occurred.

core/src/main/java/dev/vml/es/acm/core/code/CodePrintStream.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import ch.qos.logback.classic.PatternLayout;
66
import ch.qos.logback.classic.spi.ILoggingEvent;
77
import ch.qos.logback.core.OutputStreamAppender;
8-
98
import java.io.OutputStream;
109
import java.io.PrintStream;
1110
import java.util.LinkedList;

core/src/main/java/dev/vml/es/acm/core/code/ExecutionQuery.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ public class ExecutionQuery {
2727

2828
private Range<Integer> duration;
2929

30-
// TODO do more escaping e.g. for JCR illegal characters, but beware that e.g. Text.escapeIllegalJcrChars is too aggressive for paths
30+
// TODO do more escaping e.g. for JCR illegal characters
31+
// TODO beware that e.g. Text.escapeIllegalJcrChars is too aggressive for paths
3132
public static String escape(String param) {
3233
String escaped = StringUtils.replace(param, "%", "%%");
3334
return StringUtils.replace(escaped, WILDCARD, "%");

core/src/main/java/dev/vml/es/acm/core/code/FileManager.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
package dev.vml.es.acm.core.code;
22

33
import dev.vml.es.acm.core.AcmException;
4-
import org.apache.commons.io.FileUtils;
5-
import org.apache.commons.io.IOUtils;
6-
import org.apache.commons.lang3.StringUtils;
7-
import org.osgi.service.component.annotations.Component;
8-
94
import java.io.*;
105
import java.nio.file.Files;
116
import java.text.SimpleDateFormat;
127
import java.util.Collections;
138
import java.util.Date;
149
import java.util.List;
1510
import java.util.stream.Collectors;
11+
import org.apache.commons.io.FileUtils;
12+
import org.apache.commons.io.IOUtils;
13+
import org.apache.commons.lang3.StringUtils;
14+
import org.osgi.service.component.annotations.Component;
1615

1716
@Component(immediate = true, service = FileManager.class)
1817
public class FileManager {
@@ -23,15 +22,16 @@ public File root() {
2322

2423
public File get(String path) {
2524
if (!StringUtils.startsWith(path, root().getAbsolutePath())) {
26-
throw new AcmException(String.format("File path must start with the root directory'%s'!", root().getAbsolutePath()));
25+
throw new AcmException(
26+
String.format("File path must start with the root directory '%s'!", root().getAbsolutePath()));
2727
}
2828
return new File(path);
2929
}
3030

3131
public File save(InputStream stream, String fileName) {
3232
try {
3333
String datePath = new SimpleDateFormat("yyyy/MM/dd").format(new Date());
34-
String randomDir = System.currentTimeMillis() + "-" + (int)(Math.random() * 10000);
34+
String randomDir = System.currentTimeMillis() + "-" + (int) (Math.random() * 10000);
3535
File dir = new File(root(), datePath + "/" + randomDir);
3636
if (!dir.exists() && !dir.mkdirs()) {
3737
throw new AcmException("File directory cannot be created: " + dir.getAbsolutePath());

core/src/main/java/dev/vml/es/acm/core/code/arg/AbstractFileArgument.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import dev.vml.es.acm.core.code.Argument;
44
import dev.vml.es.acm.core.code.ArgumentType;
5-
65
import java.util.Arrays;
76
import java.util.Collections;
87
import java.util.List;
@@ -29,14 +28,12 @@ public void setMimeTypes(List<String> mimeTypes) {
2928

3029
public void images() {
3130
this.mimeTypes = Arrays.asList(
32-
"image/png", "image/jpeg", "image/gif", "image/webp", "image/bmp", "image/tiff", "image/svg+xml"
33-
);
31+
"image/png", "image/jpeg", "image/gif", "image/webp", "image/bmp", "image/tiff", "image/svg+xml");
3432
}
3533

3634
public void videos() {
37-
this.mimeTypes = Arrays.asList(
38-
"video/mp4", "video/webm", "video/ogg", "video/avi", "video/mpeg", "video/quicktime"
39-
);
35+
this.mimeTypes =
36+
Arrays.asList("video/mp4", "video/webm", "video/ogg", "video/avi", "video/mpeg", "video/quicktime");
4037
}
4138

4239
public void audios() {
@@ -45,9 +42,13 @@ public void audios() {
4542

4643
public void archives() {
4744
this.mimeTypes = Arrays.asList(
48-
"application/zip", "application/x-zip-compressed", "application/gzip", "application/x-gzip",
49-
"application/x-tar", "application/x-rar-compressed", "application/x-7z-compressed"
50-
);
45+
"application/zip",
46+
"application/x-zip-compressed",
47+
"application/gzip",
48+
"application/x-gzip",
49+
"application/x-tar",
50+
"application/x-rar-compressed",
51+
"application/x-7z-compressed");
5152
}
5253

5354
public void zips() {

core/src/main/java/dev/vml/es/acm/core/code/arg/FileArgument.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package dev.vml.es.acm.core.code.arg;
22

33
import dev.vml.es.acm.core.code.ArgumentType;
4-
54
import java.io.File;
65

76
public class FileArgument extends AbstractFileArgument<File> {

core/src/main/java/dev/vml/es/acm/core/code/arg/MultiFileArgument.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package dev.vml.es.acm.core.code.arg;
22

33
import dev.vml.es.acm.core.code.ArgumentType;
4-
54
import java.io.File;
65

76
public class MultiFileArgument extends AbstractFileArgument<File[]> {
@@ -29,4 +28,4 @@ public Integer getMax() {
2928
public void setMax(Integer max) {
3029
this.max = max;
3130
}
32-
}
31+
}

0 commit comments

Comments
 (0)