@@ -5,7 +5,10 @@ import (
55 "github.com/spf13/cobra"
66 "github.com/wttech/aemc/pkg"
77 "github.com/wttech/aemc/pkg/common/pathx"
8+ "github.com/wttech/aemc/pkg/common/timex"
89 "github.com/wttech/aemc/pkg/content"
10+ "os"
11+ "path/filepath"
912 "strings"
1013)
1114
@@ -17,6 +20,7 @@ func (c *CLI) contentCmd() *cobra.Command {
1720 }
1821 cmd .AddCommand (c .contentCleanCmd ())
1922 cmd .AddCommand (c .contentPullCmd ())
23+ cmd .AddCommand (c .contentPushCmd ())
2024 cmd .AddCommand (c .contentDownloadCmd ())
2125 cmd .AddCommand (c .contentCopyCmd ())
2226 return cmd
@@ -38,17 +42,17 @@ func (c *CLI) contentCleanCmd() *cobra.Command {
3842 c .Error (err )
3943 return
4044 }
45+ path := dir
46+ if path == "" {
47+ path = file
48+ }
49+ if err = c .aem .ContentManager ().Clean (path ); err != nil {
50+ c .Error (err )
51+ return
52+ }
4153 if dir != "" {
42- if err = c .aem .ContentManager ().CleanDir (dir ); err != nil {
43- c .Error (err )
44- return
45- }
4654 c .SetOutput ("dir" , dir )
4755 } else if file != "" {
48- if err = c .aem .ContentManager ().CleanFile (file ); err != nil {
49- c .Error (err )
50- return
51- }
5256 c .SetOutput ("file" , file )
5357 }
5458 c .Changed ("content cleaned" )
@@ -73,10 +77,14 @@ func (c *CLI) contentDownloadCmd() *cobra.Command {
7377 return
7478 }
7579 pid , _ := cmd .Flags ().GetString ("pid" )
80+ if pid == "" {
81+ pid = fmt .Sprintf ("aemc:content-download:%s-SNAPSHOT" , timex .FileTimestampForNow ())
82+ }
7683 targetFile , _ := cmd .Flags ().GetString ("target-file" )
77- filterRoots , _ := cmd . Flags (). GetStringSlice ( "filter-roots" )
84+ filterRoots := determineFilterRoots ( cmd )
7885 filterFile , _ := cmd .Flags ().GetString ("filter-file" )
79- if err = instance .ContentManager ().Download (targetFile , pkg.PackageCreateOpts {
86+ clean , _ := cmd .Flags ().GetBool ("clean" )
87+ if err = c .aem .ContentManager ().Download (instance , targetFile , clean , pkg.PackageCreateOpts {
8088 PID : pid ,
8189 FilterRoots : filterRoots ,
8290 FilterFile : filterFile ,
@@ -94,6 +102,7 @@ func (c *CLI) contentDownloadCmd() *cobra.Command {
94102 cmd .Flags ().StringSliceP ("filter-roots" , "r" , []string {}, "Vault filter root paths" )
95103 cmd .Flags ().StringP ("filter-file" , "f" , "" , "Vault filter file path" )
96104 cmd .MarkFlagsOneRequired ("filter-roots" , "filter-file" )
105+ cmd .Flags ().Bool ("clean" , false , "Normalize content after downloading" )
97106 return cmd
98107}
99108
@@ -108,8 +117,6 @@ func (c *CLI) contentPullCmd() *cobra.Command {
108117 c .Error (err )
109118 return
110119 }
111- clean , _ := cmd .Flags ().GetBool ("clean" )
112- replace , _ := cmd .Flags ().GetBool ("replace" )
113120 dir , err := determineContentDir (cmd )
114121 if err != nil {
115122 c .Error (err )
@@ -120,21 +127,26 @@ func (c *CLI) contentPullCmd() *cobra.Command {
120127 c .Error (err )
121128 return
122129 }
130+ filterRoots := determineFilterRoots (cmd )
131+ filterFile , _ := cmd .Flags ().GetString ("filter-file" )
132+ filterRootExcludes := determineFilterRootExcludes (cmd )
133+ clean , _ := cmd .Flags ().GetBool ("clean" )
134+ replace , _ := cmd .Flags ().GetBool ("replace" )
123135 if dir != "" {
124- filterRoots , _ := cmd .Flags ().GetStringSlice ("filter-roots" )
125- filterFile , _ := cmd .Flags ().GetString ("filter-file" )
126- if err = instance .ContentManager ().PullDir (dir , clean , replace , pkg.PackageCreateOpts {
136+ if err = c .aem .ContentManager ().PullDir (instance , dir , clean , replace , pkg.PackageCreateOpts {
137+ PID : fmt .Sprintf ("aemc:content-pull:%s-SNAPSHOT" , timex .FileTimestampForNow ()),
127138 FilterRoots : filterRoots ,
128139 FilterFile : filterFile ,
129- ContentDir : dir ,
130140 }); err != nil {
131141 c .Error (err )
132142 return
133143 }
134144 c .SetOutput ("dir" , dir )
135145 } else if file != "" {
136- if err = instance .ContentManager ().PullFile (file , clean , pkg.PackageCreateOpts {
137- ContentFile : file ,
146+ if err = c .aem .ContentManager ().PullFile (instance , file , clean , replace , pkg.PackageCreateOpts {
147+ PID : fmt .Sprintf ("aemc:content-pull:%s-SNAPSHOT" , timex .FileTimestampForNow ()),
148+ FilterRoots : filterRoots ,
149+ FilterRootExcludes : filterRootExcludes ,
138150 }); err != nil {
139151 c .Error (err )
140152 return
@@ -156,6 +168,66 @@ func (c *CLI) contentPullCmd() *cobra.Command {
156168 return cmd
157169}
158170
171+ func (c * CLI ) contentPushCmd () * cobra.Command {
172+ cmd := & cobra.Command {
173+ Use : "push" ,
174+ Aliases : []string {"ps" },
175+ Short : "Push content from JCR root directory or local file to running instance" ,
176+ Run : func (cmd * cobra.Command , args []string ) {
177+ instances , err := c .aem .InstanceManager ().Some ()
178+ if err != nil {
179+ c .Error (err )
180+ return
181+ }
182+ dir , err := determineContentDir (cmd )
183+ if err != nil {
184+ c .Error (err )
185+ return
186+ }
187+ file , err := determineContentFile (cmd )
188+ if err != nil {
189+ c .Error (err )
190+ return
191+ }
192+ path := dir
193+ if path == "" {
194+ path = file
195+ }
196+ if ! pathx .Exists (path ) {
197+ c .Error (fmt .Errorf ("cannot push content as it does not exist '%s'" , path ))
198+ return
199+ }
200+ filterRoots := determineFilterRoots (cmd )
201+ filterRootExcludes := determineFilterRootExcludes (cmd )
202+ clean , _ := cmd .Flags ().GetBool ("clean" )
203+ filterMode := determineFilterMode (cmd )
204+ if err = c .aem .ContentManager ().Push (instances , clean , pkg.PackageCreateOpts {
205+ PID : fmt .Sprintf ("aemc:content-push:%s-SNAPSHOT" , timex .FileTimestampForNow ()),
206+ FilterRoots : filterRoots ,
207+ FilterRootExcludes : filterRootExcludes ,
208+ ContentPath : path ,
209+ FilterMode : filterMode ,
210+ }); err != nil {
211+ c .Error (err )
212+ return
213+ }
214+ if dir != "" {
215+ c .SetOutput ("dir" , dir )
216+ } else if file != "" {
217+ c .SetOutput ("file" , file )
218+ }
219+ c .Changed ("content pushed" )
220+ },
221+ }
222+ cmd .Flags ().StringP ("dir" , "d" , "" , "JCR root path" )
223+ cmd .Flags ().StringP ("file" , "f" , "" , "Local file path" )
224+ cmd .Flags ().StringP ("path" , "p" , "" , "JCR root path or local file path" )
225+ cmd .MarkFlagsOneRequired ("dir" , "file" , "path" )
226+ cmd .Flags ().Bool ("clean" , false , "Normalize content while uploading" )
227+ cmd .Flags ().Bool ("update" , false , "Existing content on running instance is updated, new content is added and none is deleted" )
228+ return cmd
229+ }
230+
159231func (c * CLI ) contentCopyCmd () * cobra.Command {
160232 cmd := & cobra.Command {
161233 Use : "copy" ,
@@ -167,15 +239,16 @@ func (c *CLI) contentCopyCmd() *cobra.Command {
167239 c .Error (err )
168240 return
169241 }
170- targetInstance , err := determineContentTargetInstance (cmd , c .aem .InstanceManager ())
242+ targetInstances , err := determineContentTargetInstances (cmd , c .aem .InstanceManager ())
171243 if err != nil {
172244 c .Error (err )
173245 return
174246 }
175- filterRoots , _ := cmd . Flags (). GetStringSlice ( "filter-roots" )
247+ filterRoots := determineFilterRoots ( cmd )
176248 filterFile , _ := cmd .Flags ().GetString ("filter-file" )
177249 clean , _ := cmd .Flags ().GetBool ("clean" )
178- if err = instance .ContentManager ().Copy (targetInstance , clean , pkg.PackageCreateOpts {
250+ if err = c .aem .ContentManager ().Copy (instance , targetInstances , clean , pkg.PackageCreateOpts {
251+ PID : fmt .Sprintf ("aemc:content-copy:%s-SNAPSHOT" , timex .FileTimestampForNow ()),
179252 FilterRoots : filterRoots ,
180253 FilterFile : filterFile ,
181254 }); err != nil {
@@ -185,8 +258,8 @@ func (c *CLI) contentCopyCmd() *cobra.Command {
185258 c .Changed ("content copied" )
186259 },
187260 }
188- cmd .Flags ().StringP ("instance-target-url" , "u" , "" , "Destination instance URL" )
189- cmd .Flags ().StringP ("instance-target-id" , "i" , "" , "Destination instance ID" )
261+ cmd .Flags ().StringSliceP ("instance-target-url" , "u" , [] string {} , "Destination instance URL" )
262+ cmd .Flags ().StringSliceP ("instance-target-id" , "i" , [] string {} , "Destination instance ID" )
190263 cmd .MarkFlagsOneRequired ("instance-target-url" , "instance-target-id" )
191264 cmd .Flags ().StringSliceP ("filter-roots" , "r" , []string {}, "Vault filter root paths" )
192265 cmd .Flags ().StringP ("filter-file" , "f" , "" , "Vault filter file path" )
@@ -195,33 +268,41 @@ func (c *CLI) contentCopyCmd() *cobra.Command {
195268 return cmd
196269}
197270
198- func determineContentTargetInstance (cmd * cobra.Command , instanceManager * pkg.InstanceManager ) (* pkg.Instance , error ) {
199- var instance * pkg.Instance
200- url , _ := cmd .Flags ().GetString ("instance-target-url" )
201- if url != "" {
202- instance , _ = instanceManager .NewByIDAndURL ("remote_adhoc_target" , url )
271+ func determineContentTargetInstances (cmd * cobra.Command , instanceManager * pkg.InstanceManager ) ([]pkg.Instance , error ) {
272+ var instances []pkg.Instance
273+ urls , _ := cmd .Flags ().GetStringSlice ("instance-target-url" )
274+ for _ , url := range urls {
275+ instance , err := instanceManager .NewByIDAndURL ("remote_adhoc_target" , url )
276+ if err != nil {
277+ return nil , err
278+ }
279+ instances = append (instances , * instance )
203280 }
204- id , _ := cmd .Flags ().GetString ("instance-target-id" )
205- if id != "" {
206- instance = instanceManager .NewByID (id )
281+ ids , _ := cmd .Flags ().GetStringSlice ("instance-target-id" )
282+ for _ , id := range ids {
283+ instance := instanceManager .NewByID (id )
284+ instances = append (instances , * instance )
207285 }
208- if instance == nil {
286+ if instances == nil {
209287 return nil , fmt .Errorf ("missing 'instance-target-url' or 'instance-target-id'" )
210288 }
211- return instance , nil
289+ return instances , nil
212290}
213291
214292func determineContentDir (cmd * cobra.Command ) (string , error ) {
215293 dir , _ := cmd .Flags ().GetString ("dir" )
216294 if dir != "" && ! strings .Contains (dir , content .JCRRoot ) {
217- return "" , fmt .Errorf ("content dir '%s' does not contain '%s'" , dir , content .JCRRoot )
295+ return "" , fmt .Errorf ("content directory '%s' does not contain '%s'" , dir , content .JCRRoot )
296+ }
297+ if pathx .IsFile (dir ) {
298+ return "" , fmt .Errorf ("content directory '%s' is not a directory; consider using 'file' parameter" , dir )
218299 }
219300 path , _ := cmd .Flags ().GetString ("path" )
220301 if path != "" && ! strings .Contains (path , content .JCRRoot ) {
221302 return "" , fmt .Errorf ("content path '%s' does not contain '%s'" , path , content .JCRRoot )
222303 }
223304 if path != "" && ! pathx .Exists (path ) {
224- return "" , fmt .Errorf ("content path does not exist: %s " , path )
305+ return "" , fmt .Errorf ("content path '%s' need to exist on file system; consider using 'dir' or 'file' parameter otherwise " , path )
225306 }
226307 if path != "" && pathx .IsDir (path ) {
227308 return path , nil
@@ -234,15 +315,69 @@ func determineContentFile(cmd *cobra.Command) (string, error) {
234315 if file != "" && ! strings .Contains (file , content .JCRRoot ) {
235316 return "" , fmt .Errorf ("content file '%s' does not contain '%s'" , file , content .JCRRoot )
236317 }
318+ if pathx .IsDir (file ) {
319+ return "" , fmt .Errorf ("content file '%s' is not a file; consider using 'dir' parameter" , file )
320+ }
237321 path , _ := cmd .Flags ().GetString ("path" )
238322 if path != "" && ! strings .Contains (path , content .JCRRoot ) {
239323 return "" , fmt .Errorf ("content path '%s' does not contain '%s'" , path , content .JCRRoot )
240324 }
241325 if path != "" && ! pathx .Exists (path ) {
242- return "" , fmt .Errorf ("content path does not exist: %s " , path )
326+ return "" , fmt .Errorf ("content path '%s' need to exist on file system; consider using 'dir' or 'file' parameter otherwise " , path )
243327 }
244328 if path != "" && pathx .IsFile (path ) {
245329 return path , nil
246330 }
247331 return file , nil
248332}
333+
334+ func determineFilterRoots (cmd * cobra.Command ) []string {
335+ filterRoots , _ := cmd .Flags ().GetStringSlice ("filter-roots" )
336+ if len (filterRoots ) > 0 {
337+ return filterRoots
338+ }
339+ filterFile , _ := cmd .Flags ().GetString ("filter-file" )
340+ if filterFile != "" {
341+ return nil
342+ }
343+ dir , _ := determineContentDir (cmd )
344+ if dir != "" {
345+ return []string {pkg .DetermineFilterRoot (dir )}
346+ }
347+ file , _ := determineContentFile (cmd )
348+ if file != "" {
349+ return []string {pkg .DetermineFilterRoot (file )}
350+ }
351+ return nil
352+ }
353+
354+ func determineFilterRootExcludes (cmd * cobra.Command ) []string {
355+ file , _ := determineContentFile (cmd )
356+ if file == "" || ! strings .HasSuffix (file , content .JCRContentFile ) || content .IsPageContentFile (file ) {
357+ return nil
358+ }
359+
360+ dir := filepath .Dir (file )
361+ entries , err := os .ReadDir (dir )
362+ if err != nil {
363+ return nil
364+ }
365+
366+ var filterRootExcludes []string
367+ for _ , entry := range entries {
368+ if entry .Name () != content .JCRContentFile {
369+ jcrPath := pkg .DetermineFilterRoot (filepath .Join (dir , entry .Name ()))
370+ excludePattern := fmt .Sprintf ("%s(/.*)?" , jcrPath )
371+ filterRootExcludes = append (filterRootExcludes , excludePattern )
372+ }
373+ }
374+ return filterRootExcludes
375+ }
376+
377+ func determineFilterMode (cmd * cobra.Command ) string {
378+ update , _ := cmd .Flags ().GetBool ("update" )
379+ if update {
380+ return "update"
381+ }
382+ return ""
383+ }
0 commit comments