xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/configuration/Groups.java (revision c6f0939b1c668e9f8e1e276424439c3106b3a029)
1b5840353SAdam Hornáček /*
2b5840353SAdam Hornáček  * CDDL HEADER START
3b5840353SAdam Hornáček  *
4b5840353SAdam Hornáček  * The contents of this file are subject to the terms of the
5b5840353SAdam Hornáček  * Common Development and Distribution License (the "License").
6b5840353SAdam Hornáček  * You may not use this file except in compliance with the License.
7b5840353SAdam Hornáček  *
8b5840353SAdam Hornáček  * See LICENSE.txt included in this distribution for the specific
9b5840353SAdam Hornáček  * language governing permissions and limitations under the License.
10b5840353SAdam Hornáček  *
11b5840353SAdam Hornáček  * When distributing Covered Code, include this CDDL HEADER in each
12b5840353SAdam Hornáček  * file and include the License file at LICENSE.txt.
13b5840353SAdam Hornáček  * If applicable, add the following below this CDDL HEADER, with the
14b5840353SAdam Hornáček  * fields enclosed by brackets "[]" replaced with your own identifying
15b5840353SAdam Hornáček  * information: Portions Copyright [yyyy] [name of copyright owner]
16b5840353SAdam Hornáček  *
17b5840353SAdam Hornáček  * CDDL HEADER END
18b5840353SAdam Hornáček  */
19b5840353SAdam Hornáček 
20b5840353SAdam Hornáček /*
21*c6f0939bSAdam Hornacek  * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
22b5840353SAdam Hornáček  */
239805b761SAdam Hornáček package org.opengrok.indexer.configuration;
24b5840353SAdam Hornáček 
25b5840353SAdam Hornáček import java.io.File;
26b5840353SAdam Hornáček import java.io.FileNotFoundException;
27b5840353SAdam Hornáček import java.io.IOException;
28b5840353SAdam Hornáček import java.io.PrintStream;
29*c6f0939bSAdam Hornacek import java.nio.charset.StandardCharsets;
30b5840353SAdam Hornáček import java.text.ParseException;
31b5840353SAdam Hornáček import java.util.ArrayList;
32b5840353SAdam Hornáček import java.util.LinkedList;
33b5840353SAdam Hornáček import java.util.List;
34b5840353SAdam Hornáček import java.util.Set;
359805b761SAdam Hornáček import org.opengrok.indexer.util.Getopt;
36b5840353SAdam Hornáček 
37b5840353SAdam Hornáček /**
38b5840353SAdam Hornáček  *
39b5840353SAdam Hornáček  * @author Krystof Tulinger
40b5840353SAdam Hornáček  */
41b5840353SAdam Hornáček public final class Groups {
42b5840353SAdam Hornáček 
43b5840353SAdam Hornáček     /**
44b5840353SAdam Hornáček      * Interface used to perform an action to a single group.
45b5840353SAdam Hornáček      */
46b5840353SAdam Hornáček     private interface Walker {
47b5840353SAdam Hornáček 
48b5840353SAdam Hornáček         /**
49b5840353SAdam Hornáček          * @param g group
50b5840353SAdam Hornáček          * @return true if traversing should stop just after this group, false
51b5840353SAdam Hornáček          * otherwise
52b5840353SAdam Hornáček          */
call(Group g)53b5840353SAdam Hornáček         boolean call(Group g);
54b5840353SAdam Hornáček     }
55b5840353SAdam Hornáček 
Groups()56ff44f24aSAdam Hornáček     private Groups() {
57ff44f24aSAdam Hornáček     }
58ff44f24aSAdam Hornáček 
main(String[] argv)59b5840353SAdam Hornáček     public static void main(String[] argv) {
60b5840353SAdam Hornáček         PrintStream out = System.out;
61b5840353SAdam Hornáček         File outFile = null;
62b5840353SAdam Hornáček         Configuration cfg = new Configuration();
63b5840353SAdam Hornáček         String groupname = null;
64b5840353SAdam Hornáček         String grouppattern = null;
65b5840353SAdam Hornáček         String parent = null;
66b5840353SAdam Hornáček         boolean list = false;
67b5840353SAdam Hornáček         boolean delete = false;
68b5840353SAdam Hornáček         boolean empty = false;
69b5840353SAdam Hornáček         String match = null;
70b5840353SAdam Hornáček 
71b5840353SAdam Hornáček         Getopt getopt = new Getopt(argv, "dehi:lm:n:o:p:r:?");
72b5840353SAdam Hornáček 
73b5840353SAdam Hornáček         try {
74b5840353SAdam Hornáček             getopt.parse();
75b5840353SAdam Hornáček         } catch (ParseException ex) {
76b5840353SAdam Hornáček             System.err.println("Groups: " + ex.getMessage());
77bf9cb9d4SKryštof Tulinger             usage(System.err);
78b5840353SAdam Hornáček             System.exit(1);
79b5840353SAdam Hornáček         }
80b5840353SAdam Hornáček 
81b5840353SAdam Hornáček         try {
82b5840353SAdam Hornáček             int cmd;
83b5840353SAdam Hornáček             File f;
84b5840353SAdam Hornáček             getopt.reset();
85b5840353SAdam Hornáček             while ((cmd = getopt.getOpt()) != -1) {
86b5840353SAdam Hornáček                 switch (cmd) {
87b5840353SAdam Hornáček                     case 'd':
88b5840353SAdam Hornáček                         delete = true;
89b5840353SAdam Hornáček                         break;
90b5840353SAdam Hornáček                     case 'e':
91b5840353SAdam Hornáček                         empty = true;
92b5840353SAdam Hornáček                         break;
93b5840353SAdam Hornáček                     case 'h':
94bf9cb9d4SKryštof Tulinger                         usage(System.out);
95b5840353SAdam Hornáček                         System.exit(0);
96b5840353SAdam Hornáček                         break;
97b5840353SAdam Hornáček                     case 'i':
98b5840353SAdam Hornáček                         f = new File(getopt.getOptarg());
99b5840353SAdam Hornáček                         try {
100b5840353SAdam Hornáček                             cfg = Configuration.read(f);
101b5840353SAdam Hornáček                         } catch (ArrayIndexOutOfBoundsException ex) {
102b5840353SAdam Hornáček                             System.err.println("An error occurred - this may mean that the input file is not well-formated.");
103b5840353SAdam Hornáček                             System.err.println();
104b5840353SAdam Hornáček                             ex.printStackTrace(System.err);
105b5840353SAdam Hornáček                             System.exit(3);
106b5840353SAdam Hornáček                         }
107b5840353SAdam Hornáček                         break;
108b5840353SAdam Hornáček                     case 'l':
109b5840353SAdam Hornáček                         list = true;
110b5840353SAdam Hornáček                         break;
111b5840353SAdam Hornáček                     case 'm':
112b5840353SAdam Hornáček                         match = getopt.getOptarg();
113b5840353SAdam Hornáček                         break;
114b5840353SAdam Hornáček                     case 'n':
115b5840353SAdam Hornáček                         groupname = getopt.getOptarg();
116b5840353SAdam Hornáček                         break;
117b5840353SAdam Hornáček                     case 'o':
118b5840353SAdam Hornáček                         outFile = new File(getopt.getOptarg());
119b5840353SAdam Hornáček                         break;
120b5840353SAdam Hornáček                     case 'p':
121b5840353SAdam Hornáček                         parent = getopt.getOptarg();
122b5840353SAdam Hornáček                         break;
123b5840353SAdam Hornáček                     case 'r':
124b5840353SAdam Hornáček                         grouppattern = getopt.getOptarg();
125b5840353SAdam Hornáček                         break;
126b5840353SAdam Hornáček                     case '?':
127bf9cb9d4SKryštof Tulinger                         usage(System.out);
128b5840353SAdam Hornáček                         System.exit(0);
129b5840353SAdam Hornáček                         break;
130b5840353SAdam Hornáček                     default:
131b5840353SAdam Hornáček                         System.err.println("Internal Error - Not implemented option: " + (char) cmd);
132bf9cb9d4SKryštof Tulinger                         usage(System.err);
133b5840353SAdam Hornáček                         System.exit(1);
134b5840353SAdam Hornáček                         break;
135b5840353SAdam Hornáček                 }
136b5840353SAdam Hornáček             }
137b5840353SAdam Hornáček         } catch (FileNotFoundException ex) {
138b5840353SAdam Hornáček             System.err.println("An error occurred - file does not exist");
139b5840353SAdam Hornáček             ex.printStackTrace(System.err);
140b5840353SAdam Hornáček             System.exit(3);
141b5840353SAdam Hornáček         } catch (IOException ex) {
142b5840353SAdam Hornáček             System.err.println("An unknown error occurred - the input file may be corrupted");
143b5840353SAdam Hornáček             ex.printStackTrace(System.err);
144b5840353SAdam Hornáček             System.exit(3);
145b5840353SAdam Hornáček         }
146b5840353SAdam Hornáček 
147b5840353SAdam Hornáček         if (match != null) {
148b5840353SAdam Hornáček             // perform matching
149b5840353SAdam Hornáček             if (parent != null || groupname != null || grouppattern != null) {
150b5840353SAdam Hornáček                 System.err.println("Match option should be used without parent|groupname|groupregex options");
151bf9cb9d4SKryštof Tulinger                 usage(System.err);
152b5840353SAdam Hornáček                 System.exit(1);
153b5840353SAdam Hornáček             }
154b5840353SAdam Hornáček             matchGroups(System.out, cfg.getGroups(), match);
155b5840353SAdam Hornáček         } else if (empty) {
156b5840353SAdam Hornáček             // just list the groups
157b5840353SAdam Hornáček             if (parent != null || groupname != null || grouppattern != null) {
158b5840353SAdam Hornáček                 System.err.println("Match option should be used without parent|groupname|groupregex options");
159bf9cb9d4SKryštof Tulinger                 usage(System.err);
160b5840353SAdam Hornáček                 System.exit(1);
161b5840353SAdam Hornáček             }
162fa5f403dSTriko Trako             out = prepareOutput(outFile);
163b5840353SAdam Hornáček             printOut(false, cfg, out);
164b5840353SAdam Hornáček         } else if (delete) {
165b5840353SAdam Hornáček             // perform delete
166b5840353SAdam Hornáček             if (parent != null || grouppattern != null) {
167b5840353SAdam Hornáček                 System.err.println("Delete option should be used without parent|groupregex options");
168bf9cb9d4SKryštof Tulinger                 usage(System.err);
169b5840353SAdam Hornáček                 System.exit(1);
170b5840353SAdam Hornáček             }
171b5840353SAdam Hornáček             if (groupname == null) {
172b5840353SAdam Hornáček                 System.err.println("You must specify the group name");
173bf9cb9d4SKryštof Tulinger                 usage(System.err);
174b5840353SAdam Hornáček                 System.exit(1);
175b5840353SAdam Hornáček             }
176b5840353SAdam Hornáček             deleteGroup(cfg.getGroups(), groupname);
177b5840353SAdam Hornáček             out = prepareOutput(outFile);
178b5840353SAdam Hornáček             printOut(list, cfg, out);
179b5840353SAdam Hornáček         } else if (groupname != null) {
180b5840353SAdam Hornáček             if (grouppattern == null) {
181b5840353SAdam Hornáček                 grouppattern = "";
182b5840353SAdam Hornáček             }
183b5840353SAdam Hornáček             // perform insert/update. parent may be null
184b5840353SAdam Hornáček             if (!modifyGroup(cfg.getGroups(), groupname, grouppattern, parent)) {
185b5840353SAdam Hornáček                 System.err.println("Parent group does not exist \"" + parent + "\"");
186b5840353SAdam Hornáček             } else {
187b5840353SAdam Hornáček                 out = prepareOutput(outFile);
188b5840353SAdam Hornáček                 printOut(list, cfg, out);
189b5840353SAdam Hornáček             }
190b5840353SAdam Hornáček         } else if (list) {
191b5840353SAdam Hornáček             // just list the groups
192b5840353SAdam Hornáček             if (groupname != null) {
193b5840353SAdam Hornáček                 System.err.println("List option should be used without groupname options");
194bf9cb9d4SKryštof Tulinger                 usage(System.err);
195b5840353SAdam Hornáček                 System.exit(1);
196b5840353SAdam Hornáček             }
197b5840353SAdam Hornáček             printOut(list, cfg, out);
198b5840353SAdam Hornáček         } else {
199b5840353SAdam Hornáček             System.err.println("Wrong combination of options. See usage.");
200bf9cb9d4SKryštof Tulinger             usage(System.err);
201b5840353SAdam Hornáček             System.exit(2);
202b5840353SAdam Hornáček         }
203b5840353SAdam Hornáček     }
204b5840353SAdam Hornáček 
205b5840353SAdam Hornáček     /**
206b5840353SAdam Hornáček      * Prints the configuration to the stream.
207b5840353SAdam Hornáček      *
208b5840353SAdam Hornáček      * @param list if true then it lists all available groups in configuration
209b5840353SAdam Hornáček      * if @param out is different than stdout it also prints the current
210b5840353SAdam Hornáček      * configuration to that stream otherwise it prints the configuration to the
211b5840353SAdam Hornáček      * @param out stream.
212b5840353SAdam Hornáček      * @param cfg configuration
213b5840353SAdam Hornáček      * @param out output stream
214b5840353SAdam Hornáček      */
printOut(boolean list, Configuration cfg, PrintStream out)215b5840353SAdam Hornáček     private static void printOut(boolean list, Configuration cfg, PrintStream out) {
216b5840353SAdam Hornáček         if (list) {
217b5840353SAdam Hornáček             listGroups(System.out, cfg.getGroups());
218b5840353SAdam Hornáček             if (out != System.out) {
219b5840353SAdam Hornáček                 out.print(cfg.getXMLRepresentationAsString());
220b5840353SAdam Hornáček             }
221b5840353SAdam Hornáček         } else {
222b5840353SAdam Hornáček             out.print(cfg.getXMLRepresentationAsString());
223b5840353SAdam Hornáček         }
224b5840353SAdam Hornáček     }
225b5840353SAdam Hornáček 
prepareOutput(File outFile)226b5840353SAdam Hornáček     private static PrintStream prepareOutput(File outFile) {
227b5840353SAdam Hornáček         PrintStream out = System.out;
228b5840353SAdam Hornáček         if (outFile != null) {
229b5840353SAdam Hornáček             try {
230*c6f0939bSAdam Hornacek                 out = new PrintStream(outFile, StandardCharsets.UTF_8);
231*c6f0939bSAdam Hornacek             } catch (IOException ex) {
232*c6f0939bSAdam Hornacek                 System.err.println("An error occurred - " + ex.getMessage());
233b5840353SAdam Hornáček                 ex.printStackTrace(System.err);
234b5840353SAdam Hornáček                 System.exit(3);
235b5840353SAdam Hornáček             }
236b5840353SAdam Hornáček         }
237b5840353SAdam Hornáček         return out;
238b5840353SAdam Hornáček     }
239b5840353SAdam Hornáček 
240b5840353SAdam Hornáček     /**
241b5840353SAdam Hornáček      * List groups given as a parameter.
242b5840353SAdam Hornáček      *
243b5840353SAdam Hornáček      * @param out stream
244b5840353SAdam Hornáček      * @param groups groups
245b5840353SAdam Hornáček      */
listGroups(PrintStream out, Set<Group> groups)246b5840353SAdam Hornáček     private static void listGroups(PrintStream out, Set<Group> groups) {
247*c6f0939bSAdam Hornacek         treeTraverseGroups(groups, g -> {
248b5840353SAdam Hornáček             for (int i = 0; i < g.getFlag() * 2; i++) {
249b5840353SAdam Hornáček                 out.print(" ");
250b5840353SAdam Hornáček             }
251b5840353SAdam Hornáček             out.println(g.getName() + " ~ '" + g.getPattern() + "'");
252b5840353SAdam Hornáček             return false;
253b5840353SAdam Hornáček         });
254b5840353SAdam Hornáček     }
255b5840353SAdam Hornáček 
256b5840353SAdam Hornáček     /**
257b5840353SAdam Hornáček      * Finds groups which would match the project.
258b5840353SAdam Hornáček      *
259b5840353SAdam Hornáček      * @param out stream to write the results
260b5840353SAdam Hornáček      * @param groups set of groups
261b5840353SAdam Hornáček      * @param match project name
262b5840353SAdam Hornáček      */
matchGroups(PrintStream out, Set<Group> groups, String match)263b5840353SAdam Hornáček     private static void matchGroups(PrintStream out, Set<Group> groups, String match) {
264b5840353SAdam Hornáček         Project p = new Project(match);
265b5840353SAdam Hornáček 
266b5840353SAdam Hornáček         List<Group> matched = new ArrayList<>();
267*c6f0939bSAdam Hornacek         linearTraverseGroups(groups, g -> {
268b5840353SAdam Hornáček             if (g.match(p)) {
269b5840353SAdam Hornáček                 matched.add(g);
270b5840353SAdam Hornáček             }
271b5840353SAdam Hornáček             return false;
272b5840353SAdam Hornáček         });
273b5840353SAdam Hornáček 
274b5840353SAdam Hornáček         out.println(matched.size() + " group(s) match(es) the \"" + match + "\"");
275b5840353SAdam Hornáček         for (Group g : matched) {
276b5840353SAdam Hornáček             out.println(g.getName() + " '" + g.getPattern() + "'");
277b5840353SAdam Hornáček         }
278b5840353SAdam Hornáček     }
279b5840353SAdam Hornáček 
280b5840353SAdam Hornáček     /**
281b5840353SAdam Hornáček      * Adds a group into the xml tree.
282b5840353SAdam Hornáček      *
283b5840353SAdam Hornáček      * If group already exists, only the pattern is modified. Parent group can
284b5840353SAdam Hornáček      * be null, in that case a new group is inserted as a top level group.
285b5840353SAdam Hornáček      *
286b5840353SAdam Hornáček      * @param groups existing groups
287b5840353SAdam Hornáček      * @param groupname new group name
288b5840353SAdam Hornáček      * @param grouppattern new group pattern
289b5840353SAdam Hornáček      * @param parent parent
290b5840353SAdam Hornáček      * @return false if parent group was not found, true otherwise
291b5840353SAdam Hornáček      */
modifyGroup(Set<Group> groups, String groupname, String grouppattern, String parent)292b5840353SAdam Hornáček     private static boolean modifyGroup(Set<Group> groups, String groupname, String grouppattern, String parent) {
293b5840353SAdam Hornáček         Group g = new Group(groupname, grouppattern);
294b5840353SAdam Hornáček 
295b5840353SAdam Hornáček         if (updateGroup(groups, groupname, grouppattern)) {
296b5840353SAdam Hornáček             return true;
297b5840353SAdam Hornáček         }
298b5840353SAdam Hornáček 
299b5840353SAdam Hornáček         if (parent != null) {
300b5840353SAdam Hornáček             if (insertToParent(groups, parent, g)) {
301b5840353SAdam Hornáček                 groups.add(g);
302b5840353SAdam Hornáček                 return true;
303b5840353SAdam Hornáček             }
304b5840353SAdam Hornáček             return false;
305b5840353SAdam Hornáček         }
306b5840353SAdam Hornáček 
307b5840353SAdam Hornáček         groups.add(g);
308b5840353SAdam Hornáček         return true;
309b5840353SAdam Hornáček     }
310b5840353SAdam Hornáček 
311b5840353SAdam Hornáček     /**
312b5840353SAdam Hornáček      * Removes group from the xml tree.
313b5840353SAdam Hornáček      *
314b5840353SAdam Hornáček      * @param groups existing groups
315b5840353SAdam Hornáček      * @param groupname group to remove
316b5840353SAdam Hornáček      */
deleteGroup(Set<Group> groups, String groupname)317b5840353SAdam Hornáček     private static void deleteGroup(Set<Group> groups, String groupname) {
318b5840353SAdam Hornáček         for (Group g : groups) {
319b5840353SAdam Hornáček             if (g.getName().equals(groupname)) {
320b5840353SAdam Hornáček                 groups.remove(g);
321b5840353SAdam Hornáček                 groups.removeAll(g.getDescendants());
322b5840353SAdam Hornáček                 return;
323b5840353SAdam Hornáček             }
324b5840353SAdam Hornáček         }
325b5840353SAdam Hornáček     }
326b5840353SAdam Hornáček 
327b5840353SAdam Hornáček     /**
328b5840353SAdam Hornáček      * Traverse the set of groups starting in top level groups (groups without a
329b5840353SAdam Hornáček      * parent group) and performing depth first search in the group's subgroups.
330b5840353SAdam Hornáček      *
331b5840353SAdam Hornáček      * @param groups set of groups (mixed top level and other groups)
332b5840353SAdam Hornáček      * @param walker an instance of {@link Walker} which is used for every
333b5840353SAdam Hornáček      * traversed group
334b5840353SAdam Hornáček      * @return true if {@code walker} emits true for any of the groups; false
335b5840353SAdam Hornáček      * otherwise
336b5840353SAdam Hornáček      *
337b5840353SAdam Hornáček      * @see Walker
338b5840353SAdam Hornáček      */
treeTraverseGroups(Set<Group> groups, Walker walker)339b5840353SAdam Hornáček     private static boolean treeTraverseGroups(Set<Group> groups, Walker walker) {
340b5840353SAdam Hornáček         LinkedList<Group> stack = new LinkedList<>();
341b5840353SAdam Hornáček         for (Group g : groups) {
342b5840353SAdam Hornáček             // the flag here represents the group's depth in the group tree
343b5840353SAdam Hornáček             g.setFlag(0);
344b5840353SAdam Hornáček             if (g.getParent() == null) {
345b5840353SAdam Hornáček                 stack.addLast(g);
346b5840353SAdam Hornáček             }
347b5840353SAdam Hornáček         }
348b5840353SAdam Hornáček 
349b5840353SAdam Hornáček         while (!stack.isEmpty()) {
350b5840353SAdam Hornáček             Group g = stack.getFirst();
351b5840353SAdam Hornáček             stack.removeFirst();
352b5840353SAdam Hornáček 
353b5840353SAdam Hornáček             if (walker.call(g)) {
354b5840353SAdam Hornáček                 return true;
355b5840353SAdam Hornáček             }
356b5840353SAdam Hornáček 
357*c6f0939bSAdam Hornacek             g.getSubgroups().forEach(x -> x.setFlag(g.getFlag() + 1));
358b5840353SAdam Hornáček             // add all the subgroups respecting the sorted order
359b5840353SAdam Hornáček             stack.addAll(0, g.getSubgroups());
360b5840353SAdam Hornáček         }
361b5840353SAdam Hornáček         return false;
362b5840353SAdam Hornáček     }
363b5840353SAdam Hornáček 
364b5840353SAdam Hornáček     /**
365b5840353SAdam Hornáček      * Traverse the set of groups linearly based on the set's iterator.
366b5840353SAdam Hornáček      *
367b5840353SAdam Hornáček      * @param groups set of groups (mixed top level and other groups)
368b5840353SAdam Hornáček      * @param walker an instance of {@link Walker} which is used for every
369b5840353SAdam Hornáček      * traversed group
370b5840353SAdam Hornáček      * @return true if {@code walker} emits true for any of the groups; false
371b5840353SAdam Hornáček      */
linearTraverseGroups(Set<Group> groups, Walker walker)372b5840353SAdam Hornáček     private static boolean linearTraverseGroups(Set<Group> groups, Walker walker) {
373b5840353SAdam Hornáček         for (Group g : groups) {
374b5840353SAdam Hornáček             if (walker.call(g)) {
375b5840353SAdam Hornáček                 return true;
376b5840353SAdam Hornáček             }
377b5840353SAdam Hornáček         }
378b5840353SAdam Hornáček         return false;
379b5840353SAdam Hornáček     }
380b5840353SAdam Hornáček 
insertToParent(Set<Group> groups, String parent, Group g)381b5840353SAdam Hornáček     private static boolean insertToParent(Set<Group> groups, String parent, Group g) {
382*c6f0939bSAdam Hornacek         return linearTraverseGroups(groups, x -> {
383b5840353SAdam Hornáček             if (x.getName().equals(parent)) {
384b5840353SAdam Hornáček                 x.addGroup(g);
385b5840353SAdam Hornáček                 Group tmp = x.getParent();
386b5840353SAdam Hornáček                 while (tmp != null) {
387b5840353SAdam Hornáček                     tmp.addDescendant(g);
388b5840353SAdam Hornáček                     tmp = tmp.getParent();
389b5840353SAdam Hornáček                 }
390b5840353SAdam Hornáček                 return true;
391b5840353SAdam Hornáček             }
392b5840353SAdam Hornáček             return false;
393b5840353SAdam Hornáček         });
394b5840353SAdam Hornáček     }
395b5840353SAdam Hornáček 
396b5840353SAdam Hornáček     private static boolean updateGroup(Set<Group> groups, String groupname, String grouppattern) {
397*c6f0939bSAdam Hornacek         return linearTraverseGroups(groups, g -> {
398b5840353SAdam Hornáček             if (g.getName().equals(groupname)) {
399b5840353SAdam Hornáček                 g.setPattern(grouppattern);
400b5840353SAdam Hornáček                 return true;
401b5840353SAdam Hornáček             }
402b5840353SAdam Hornáček             return false;
403b5840353SAdam Hornáček         });
404b5840353SAdam Hornáček     }
405b5840353SAdam Hornáček 
406d1e826faSAdam Hornáček     private static void usage(PrintStream out) {
407bf9cb9d4SKryštof Tulinger         out.println("Usage:");
408bf9cb9d4SKryštof Tulinger         out.println("Groups.java" + " [OPTIONS]");
409bf9cb9d4SKryštof Tulinger         out.println();
410bf9cb9d4SKryštof Tulinger         out.println("OPTIONS:");
411bf9cb9d4SKryštof Tulinger         out.println("Help");
412bf9cb9d4SKryštof Tulinger         out.println("-?                   print this help message");
413bf9cb9d4SKryštof Tulinger         out.println("-h                   print this help message");
414bf9cb9d4SKryštof Tulinger         out.println("-v                   verbose/debug mode");
415bf9cb9d4SKryštof Tulinger         out.println();
416bf9cb9d4SKryštof Tulinger         out.println("Input/Output");
417bf9cb9d4SKryštof Tulinger         out.println("-i /path/to/file     input file|default is empty configuration");
418bf9cb9d4SKryštof Tulinger         out.println("-o /path/to/file     output file|default is stdout");
419bf9cb9d4SKryštof Tulinger         out.println();
420bf9cb9d4SKryštof Tulinger         out.println("Listing");
421bf9cb9d4SKryštof Tulinger         out.println("-m <project name>    performs matching based on given project name");
422bf9cb9d4SKryštof Tulinger         out.println("-l                   lists all available groups in input file");
423bf9cb9d4SKryštof Tulinger         out.println("-e                   creates an empty configuration or");
424bf9cb9d4SKryštof Tulinger         out.println("                     directly outputs the input file (if given)");
425bf9cb9d4SKryštof Tulinger         out.println();
426bf9cb9d4SKryštof Tulinger         out.println("Modification");
427bf9cb9d4SKryštof Tulinger         out.println("-n <group name>      specify group name which should be inserted|updated (requires either -r or -d option)");
428bf9cb9d4SKryštof Tulinger         out.println("-r <group regex>     specify group regex pattern (requires -n option)");
429bf9cb9d4SKryštof Tulinger         out.println("-p <parent group>    optional parameter for the parent group name (requires -n option)");
430bf9cb9d4SKryštof Tulinger         out.println("-d                   delete specified group (requires -n option)");
431bf9cb9d4SKryštof Tulinger         out.println();
432bf9cb9d4SKryštof Tulinger         out.println("NOTE: using modification options with -l forces the program to list all\n"
433b5840353SAdam Hornáček                 + "available groups after the modification. Output to a file can still be used.");
434bf9cb9d4SKryštof Tulinger         out.println();
435bf9cb9d4SKryštof Tulinger         out.println("Examples");
436bf9cb9d4SKryštof Tulinger         out.println("-i ~/c.xml -l                     # => list groups");
437bf9cb9d4SKryštof Tulinger         out.println("-n Abcd -r \"abcd.*\" -o ~/c.xml    # => add group and print to ~/c.xml");
438bf9cb9d4SKryštof Tulinger         out.println("-i ~/c.xml -m abcdefg             # => prints groups which would match this project description");
439bf9cb9d4SKryštof Tulinger         out.println("-i ~/c.xml -d -n Abcd             # => deletes group Abcd");
440bf9cb9d4SKryštof Tulinger         out.println("-n Bcde -r \".*bcde.*\" -l          # => add group and lists the result");
441b5840353SAdam Hornáček     }
442b5840353SAdam Hornáček }
443