1 | aemsync
|
2 | =======
|
3 |
|
4 | The code and content synchronization for Sling / AEM (Adobe Experience Manager).
|
5 |
|
6 | ### Synopsis
|
7 |
|
8 | The tool pushes content to AEM instance(s) upon a file change.
|
9 | * There is no vault dependency.
|
10 | * It can push to multiple instances at the same time (e.g. author and publish).
|
11 | * IDE / editor agnostic.
|
12 | * Works on Windows, Linux and Mac.
|
13 |
|
14 | ### Installation
|
15 |
|
16 | With [npm](http://npmjs.org) do:
|
17 |
|
18 | ```
|
19 | npm install aemsync -g
|
20 | ```
|
21 |
|
22 | ### Usage
|
23 |
|
24 | Simply run `aemsync` on your project path, make a change to any of your files or directories and watch the magic happen.
|
25 |
|
26 | ### Advanced usage
|
27 |
|
28 | Commandline
|
29 | ```
|
30 | Usage:
|
31 | aemsync [OPTIONS]
|
32 |
|
33 | Options:
|
34 | -t <target> URL to AEM instance; multiple can be set.
|
35 | Default: ${defaults.targets}
|
36 | -w <path_to_watch> Watch over folder.
|
37 | Default: CWD
|
38 | -p <path_to_push> Push specific file or folder.
|
39 | -e <exclude_filter> Extended glob filter; multiple can be set.
|
40 | Default:
|
41 | **/jcr_root/*
|
42 | **/@(.git|.svn|.hg|target)
|
43 | **/@(.git|.svn|.hg|target)/**
|
44 | -i <sync_interval> Update interval.
|
45 | Default: ${defaults.interval} ms
|
46 | -u <packmgr_path> Package manager path.
|
47 | Default: ${defaults.packmgrPath}
|
48 | -c Check if AEM is up and running before pushing.
|
49 | -d Enable debug mode.
|
50 | -h Display this screen.
|
51 |
|
52 | Examples:
|
53 | Magic:
|
54 | > aemsync
|
55 | Custom targets:
|
56 | > aemsync -t http://admin:admin@localhost:4502 -t http://admin:admin@localhost:4503 -w ~/workspace/my_project
|
57 | Custom exclude rules:
|
58 | > aemsync -e **/*.orig -e **/test -e -e **/test/**
|
59 | Just push, don't watch:
|
60 | > aemsync -p /foo/bar/my-workspace/jcr_content/apps/my-app/components/my-component
|
61 | ```
|
62 |
|
63 | JavaScript (full watch example):
|
64 | ```JavaScript
|
65 | const aemsync = require('aemsync')
|
66 |
|
67 | const workingDir = '~/workspace/my_project'
|
68 |
|
69 | // Arguments below are optional.
|
70 | const targets = [
|
71 | 'http://admin:admin@localhost:4502',
|
72 | 'http://admin:admin@localhost:4503'
|
73 | ]
|
74 | const exclude = ['**/*.orig'] // Skip merge files.
|
75 | const packmgrPath = '/foo/crx/packmgr/service.jsp'
|
76 | const interval = 300
|
77 | const onPushEnd = (err, target, log) => {
|
78 | // Called for each of the targets.
|
79 | if (err) {
|
80 | console.log(`Error when pushing package to ${target}.`, err.message)
|
81 | } else {
|
82 | console.log(`Package pushed to ${target}. Response log:\n${log}`)
|
83 | }
|
84 | }
|
85 | const checkBeforePush = true
|
86 |
|
87 | // Will watch for changes over workingDir and push upon a file change.
|
88 | // Only the first argument is mandatory.
|
89 | aemsync(workingDir, { targets, exclude, interval, packmgrPath, onPushEnd, checkBeforePush })
|
90 | ```
|
91 |
|
92 | JavaScript (direct push example):
|
93 | ```JavaScript
|
94 | const { push } = require('aemsync')
|
95 |
|
96 | const pathToPush = '~/foo/bar/my-workspace/jcr_content/apps/my-app/components/my-component'
|
97 |
|
98 | // Arguments below are optional.
|
99 | const targets = [
|
100 | 'http://admin:admin@localhost:4502',
|
101 | 'http://admin:admin@localhost:4503'
|
102 | ]
|
103 | const onPushEnd = (err, target, log) => {
|
104 | // Called for each of the targets.
|
105 | if (err) {
|
106 | console.log(`Error when pushing package to ${target}.`, err.message)
|
107 | } else {
|
108 | console.log(`Package pushed to ${target}. Response log:\n${log}`)
|
109 | }
|
110 | }
|
111 | const checkBeforePush = true
|
112 |
|
113 | // Will push the path to AEM.
|
114 | // To use await, the call must be made inside an async function.
|
115 | // The result is a Promise so it can also be resolved with .then().
|
116 | // Only the first argument is mandatory.
|
117 | await push(pathToPush, { targets, onPushEnd, checkBeforePush })
|
118 | ```
|
119 |
|
120 | ### Description
|
121 |
|
122 | The Watcher uses Node's `fs.watch()` function to watch over directory changes recursively. For Windows and OSX the `recursive` option is used, which significantly improves the performance.
|
123 |
|
124 | Any changes inside `jcr_root` folders are detected and deployed to AEM instance(s) as a package. By default, there is an exclude filter in palce:
|
125 | * Changes to first level directories under `jcr_root` are ingored. This is to avoid accidentally removing `apps`, `libs` or any other first level node in AEM.
|
126 | * Any paths containing `.svn`, `.git`, `.hg` or `target` are ignored.
|
127 | * The exclude filter can be overriden. Do note that this will remove the above rules completely and if required, they must be added manually.
|
128 |
|
129 | Update interval is the time aemsync waits for file changes before the package is created. In case of multiple file changes (e.g. switching between code branches), creating a new package per file should be avoided and instead, all changes should be pushed in one go. Lowering the value decreases the delay for a single file change but may increase the delay for multiple file changes. If you are unsure, please leave the default value.
|
130 |
|
131 | ### Caveats
|
132 |
|
133 | 1. Packages are installed using package manager service (`/crx/packmgr/service.jsp`), which takes some time to initialize after AEM startup. If the push happens before, the Sling Post Servlet will take over causing the `/crx/packmgr/service.jsp/file` node to be added to the repository. Use `-c` option to performs a status check before sending (all bundles must be active).
|
134 | 2. Changing any XML file will cause the parent folder to be pushed. Given the many special cases around XML files, the handlig is left to the package manager.
|
135 |
|
136 | ### Backward incompatible changes since version 4
|
137 |
|
138 | 1. Multiple targes are now specified with multiple `-t` options rather than a comma separated string.
|
139 | 2. The same goes for the exclude filter (`-e`).
|
140 | 3. Exclude filter supports extended globbing only. Setting exclude filter with `-e` option overrides the default.
|
141 | 4. JavaScript API functions have a different signature. This is to spearate mandatory and optional arguments.
|
142 | 5. The `push()` function returns Promise and can be resolved with `await`.
|