Martin Peřina has uploaded a new change for review.

Change subject: core: Adds cli parser supporting short and long args
......................................................................

core: Adds cli parser supporting short and long args

Adds command line arguments parser that supports parsing short (-h) and
long arguments (--help).

Change-Id: Id7fe3bf761bd26c86d684ad1dc85751d4492239b
Bug-Url: https://bugzilla.redhat.com/904029
Signed-off-by: Martin Perina <mper...@redhat.com>
---
A 
backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/cli/Argument.java
A 
backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/cli/ArgumentBuilder.java
A 
backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/cli/ExtendedCliParser.java
A 
backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/cli/ArgumentBuilderTest.java
A 
backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/cli/ExtendedCliParserTest.java
5 files changed, 770 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/95/23995/1

diff --git 
a/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/cli/Argument.java
 
b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/cli/Argument.java
new file mode 100644
index 0000000..4d15785
--- /dev/null
+++ 
b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/cli/Argument.java
@@ -0,0 +1,37 @@
+package org.ovirt.engine.core.utils.cli;
+
+/**
+ * Represents argument specification inside {@link ExtendedCliParser}
+ */
+class Argument {
+    private final String shortName;
+
+    private final String longName;
+
+    private final String destination;
+
+    private final boolean valueRequired;
+
+    Argument(String shortName, String longName, String destination, boolean 
valueRequired) {
+        this.shortName = shortName;
+        this.longName = longName;
+        this.destination = destination;
+        this.valueRequired = valueRequired;
+    }
+
+    public String getShortName() {
+        return shortName;
+    }
+
+    public String getLongName() {
+        return longName;
+    }
+
+    public String getDestination() {
+        return destination;
+    }
+
+    public boolean isValueRequied() {
+        return valueRequired;
+    }
+}
diff --git 
a/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/cli/ArgumentBuilder.java
 
b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/cli/ArgumentBuilder.java
new file mode 100644
index 0000000..1215973
--- /dev/null
+++ 
b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/cli/ArgumentBuilder.java
@@ -0,0 +1,86 @@
+package org.ovirt.engine.core.utils.cli;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Builder to create arguments for {@link ExtendedCliParser}
+ */
+public class ArgumentBuilder {
+    private String shortName;
+    private String longName;
+    private String destination;
+    private boolean valueRequired;
+
+    public ArgumentBuilder() {
+        valueRequired = false;
+    }
+
+    /**
+     * Sets short name of argument
+     *
+     * @param shortName
+     *            short name of argument
+     * @returns builder instance
+     */
+    public ArgumentBuilder shortName(String shortName) {
+        this.shortName = shortName;
+        return this;
+    }
+
+    /**
+     * Sets long name of argument
+     *
+     * @param longName
+     *            long name of argument
+     * @returns builder instance
+     */
+    public ArgumentBuilder longName(String longName) {
+        this.longName = longName;
+        return this;
+    }
+
+    /**
+     * Sets destination of argument
+     *
+     * @param destination
+     *            destination of argument
+     * @returns builder instance
+     */
+    public ArgumentBuilder destination(String destination) {
+        this.destination = destination;
+        return this;
+    }
+
+    /**
+     * Sets indicator if value is required
+     *
+     * @param valueRequired
+     *            indicator if value is required
+     * @returns builder instance
+     */
+    public ArgumentBuilder valueRequied(boolean valueRequired) {
+        this.valueRequired = valueRequired;
+        return this;
+    }
+
+    /**
+     * Builds argument. If destination is empty, it's set long name (or short 
name if long name is also empty). By
+     * default argument value is not required
+     */
+    public Argument build() {
+        if (StringUtils.isBlank(shortName)
+                && StringUtils.isBlank(longName)) {
+            throw new IllegalArgumentException("Argument must have non-empty 
short or long name!");
+        }
+
+        if (StringUtils.isBlank(destination)) {
+            if (StringUtils.isNotBlank(longName)) {
+                destination = longName;
+            } else {
+                destination = shortName;
+            }
+        }
+
+        return new Argument(shortName, longName, destination, valueRequired);
+    }
+}
diff --git 
a/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/cli/ExtendedCliParser.java
 
b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/cli/ExtendedCliParser.java
new file mode 100644
index 0000000..79e172f
--- /dev/null
+++ 
b/backend/manager/modules/utils/src/main/java/org/ovirt/engine/core/utils/cli/ExtendedCliParser.java
@@ -0,0 +1,234 @@
+package org.ovirt.engine.core.utils.cli;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Implements argument parser, that supports parsing short and long arguments
+ */
+public class ExtendedCliParser {
+    /**
+     * Short argument prefix
+     */
+    static final String PREFIX_SHORT = "-";
+
+    /**
+     * Long argument prefix
+     */
+    static final String PREFIX_LONG = "--";
+
+    /**
+     * Long argument value separator
+     */
+    static final String VALUE_SEP_LONG = "=";
+
+    /**
+     * Map of argument names and their instances
+     */
+    Map<String, Argument> argMap;
+
+    /**
+     * Initializes set of arguments
+     */
+    public ExtendedCliParser() {
+        argMap = new HashMap<>();
+    }
+
+    /**
+     * Adds argument to parser
+     *
+     * @param arg
+     *            specified argument
+     */
+    public void addArg(Argument arg) {
+        if (StringUtils.isNotBlank(arg.getShortName())
+                && argMap.containsKey(arg.getShortName())) {
+            throw new IllegalArgumentException(
+                    String.format("Argument with short name '%s' already 
exists!", arg.getShortName()));
+        }
+
+        if (StringUtils.isNotBlank(arg.getLongName())
+                && argMap.containsKey(arg.getLongName())) {
+            throw new IllegalArgumentException(
+                    String.format("Argument with long name '%s' already 
exists!", arg.getLongName()));
+        }
+
+        if (arg.getShortName() != null) {
+            argMap.put(arg.getShortName(), arg);
+        }
+        if (arg.getLongName() != null) {
+            argMap.put(arg.getLongName(), arg);
+        }
+    }
+
+    /**
+     * Parses arguments in {@code args} and returns map with argument names 
and their values
+     *
+     * @param args
+     *            array of arguments (usually command line arguments splitted 
by space)
+     * @throws IllegalArgumentException
+     *             if {@code args} is {@code null} or arguments has invalid 
format
+     * @return map with argument names and their values
+     */
+    public Map<String, String> parse(String[] args) {
+        if (args == null) {
+            throw new IllegalArgumentException("Argumens array cannot be 
null");
+        }
+
+        return parse(args, 0, args.length);
+    }
+
+    /**
+     * Parses arguments in {@code args} between specified array indexes and 
returns map with argument names and their
+     * values
+     *
+     * @param args
+     *            array of arguments (usually command line arguments splitted 
by space)
+     * @param from
+     *            starting index
+     * @param to
+     *            end index
+     * @throws IllegalArgumentException
+     *             if {@code args} is {@code null} or arguments has invalid 
format
+     * @throws ArrayIndexOutOfBoundsException
+     *             if indexes {@code from} or {@code to} are invalid
+     * @return map with argument names and their values
+     */
+    public Map<String, String> parse(String[] args, int from, int to) {
+        if (args == null) {
+            throw new IllegalArgumentException("Argumens array cannot be 
null");
+        }
+
+        Map<String, String> result = new HashMap<>();
+        // parse arguments
+        for (int i = from; i < to;) {
+            if (args[i] == null) {
+                // just to be sure
+                i++;
+                continue;
+            }
+
+            String name = null;
+            String value = null;
+
+            if (isLongArg(args[i])) {
+                // parse long argument
+                name = parseLongArgName(args[i]);
+                value = parseLongArgValue(args[i]);
+            } else if (isShortArg(args[i])) {
+                // parse short argument
+                name = args[i];
+                if (i + 1 < args.length) {
+                    if (!isShortArg(args[i + 1]) && !isLongArg(args[i + 1])) {
+                        // argument has a value
+                        value = args[i + 1];
+                        i++;
+                    }
+                }
+            } else {
+                // invalid argument format
+                throw new IllegalArgumentException(
+                        String.format("Invalid argument format '%s'!", 
args[i]));
+            }
+
+            Argument arg = argMap.get(name);
+            if (arg == null) {
+                throw new IllegalArgumentException(
+                        String.format("Unknown argument '%s'!", name));
+            }
+            if (arg.isValueRequied() && StringUtils.isBlank(value)) {
+                throw new IllegalArgumentException(
+                        String.format("Argument '%s' requires value!", name));
+            }
+            result.put(arg.getDestination(), value);
+            i++;
+        }
+        return result;
+    }
+
+    /**
+     * Tests if specified argument contains valid short argument name
+     *
+     * @param arg
+     *            argument
+     * @return {@code true} if string contains valid short argument, otherwise 
{@code false}
+     */
+    private boolean isShortArg(String arg) {
+        boolean result = true;
+        if (arg == null || arg.length() != 2) {
+            result = false;
+        } else if (!arg.startsWith(PREFIX_SHORT)) {
+            result = false;
+        } else if (!Character.isLetterOrDigit(arg.charAt(1))) {
+            result = false;
+        }
+        return result;
+    }
+
+    /**
+     * Tests if specified argument contains valid long argument name.
+     *
+     * @param arg
+     *            argument
+     * @return {@code true} if string contains valid long argument, otherwise 
{@code false}
+     */
+    private boolean isLongArg(String arg) {
+        boolean result = true;
+        if (arg == null || arg.length() < 3) {
+            result = false;
+        } else if (!arg.startsWith(PREFIX_LONG)) {
+            result = false;
+        } else {
+            for (int i = 2; i < arg.length(); i++) {
+                if (i > 2 && i + 2 < arg.length() && 
VALUE_SEP_LONG.equals(arg.substring(i, i + 1))) {
+                    // argument contains value
+                    break;
+                }
+                char c = arg.charAt(i);
+                if (!Character.isLetterOrDigit(c) && c != '-') {
+                    result = false;
+                    break;
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Parses name of long argument from specified string. Method DOES NOT 
validate argument, it just creates
+     * substring from start to value separator (or to the end if separator is 
not present) and removes prefix.
+     *
+     * @param str
+     *            specified string
+     * @returns long argument name
+     */
+    private String parseLongArgName(String str) {
+        int idx = str.indexOf(VALUE_SEP_LONG);
+        if (idx == -1) {
+            // argument does not contain value
+            return str;
+        } else {
+            return str.substring(0, idx);
+        }
+    }
+
+    /**
+     * Parses value of long argument from specified string. Method DOES NOT 
validate argument, it just creates
+     * substring value separator to the end or returns {@code null} if value 
separator is not present
+     *
+     * @param str
+     *            specified string
+     * @returns long argument value or {@code null}
+     */
+    private String parseLongArgValue(String str) {
+        int idx = str.indexOf(VALUE_SEP_LONG);
+        if (idx == -1) {
+            // arg does not contain value
+            return null;
+        } else {
+            return str.substring(idx + 1);
+        }
+    }
+}
diff --git 
a/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/cli/ArgumentBuilderTest.java
 
b/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/cli/ArgumentBuilderTest.java
new file mode 100644
index 0000000..f2d72a3
--- /dev/null
+++ 
b/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/cli/ArgumentBuilderTest.java
@@ -0,0 +1,142 @@
+package org.ovirt.engine.core.utils.cli;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for argument creation used by {@link ExtendedCliParser}
+ */
+@RunWith(JUnit4.class)
+public class ArgumentBuilderTest {
+    /**
+     * Tests creating argument without value required specified
+     */
+    @Test
+    public void createValidArgWithoutRequiredSpecified() {
+        String shortName = "-h";
+        String longName = "--help";
+        String destination = "dest";
+
+        Argument arg = new ArgumentBuilder()
+                .shortName(shortName)
+                .longName(longName)
+                .destination(destination)
+                .build();
+
+        assertEquals(shortName, arg.getShortName());
+        assertEquals(longName, arg.getLongName());
+        assertEquals(destination, arg.getDestination());
+        assertFalse(arg.isValueRequied());
+    }
+
+    /**
+     * Tests creating argument with value required specified
+     */
+    @Test
+    public void createValidArgWithRequiredSpecified() {
+        String shortName = "-h";
+        String longName = "--help";
+        String destination = "dest";
+
+        Argument arg = new ArgumentBuilder()
+                .shortName(shortName)
+                .longName(longName)
+                .destination(destination)
+                .valueRequied(true)
+                .build();
+
+        assertEquals(shortName, arg.getShortName());
+        assertEquals(longName, arg.getLongName());
+        assertEquals(destination, arg.getDestination());
+        assertTrue(arg.isValueRequied());
+    }
+
+    /**
+     * Tests creating argument with only short name
+     */
+    @Test
+    public void createValidArgWithOnlyShortName() {
+        String shortName = "-h";
+
+        Argument arg = new ArgumentBuilder()
+                .shortName(shortName)
+                .build();
+
+        assertEquals(shortName, arg.getShortName());
+    }
+
+    /**
+     * Tests creating argument with only long name
+     */
+    @Test
+    public void createValidArgWithOnlyLongName() {
+        String longName = "--help";
+
+        Argument arg = new ArgumentBuilder()
+                .longName(longName)
+                .build();
+
+        assertEquals(longName, arg.getLongName());
+    }
+
+    /**
+     * Tests creating argument without short and long name
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void createArgWithoutShortAndLongNames() {
+        new ArgumentBuilder().destination("dest").build();
+    }
+
+    /**
+     * Tests destination defined by destination option
+     */
+    @Test
+    public void parseArgsWithDestDefinedByDest() {
+        String shortName = "-h";
+        String longName = "--help";
+        String destination = "dest";
+
+        Argument arg = new ArgumentBuilder()
+                .shortName(shortName)
+                .longName(longName)
+                .destination(destination)
+                .build();
+
+        assertEquals(destination, arg.getDestination());
+    }
+
+    /**
+     * Tests destination defined by long name option
+     */
+    @Test
+    public void parseArgsWithDestDefinedByLongName() {
+        String shortName = "-h";
+        String longName = "--help";
+
+        Argument arg = new ArgumentBuilder()
+                .shortName(shortName)
+                .longName(longName)
+                .build();
+
+        assertEquals(longName, arg.getDestination());
+    }
+
+    /**
+     * Tests destination defined by short name option
+     */
+    @Test
+    public void parseArgsWithDestDefinedByShortName() {
+        String shortName = "-h";
+
+        Argument arg = new ArgumentBuilder()
+                .shortName(shortName)
+                .build();
+
+        assertEquals(shortName, arg.getDestination());
+    }
+}
diff --git 
a/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/cli/ExtendedCliParserTest.java
 
b/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/cli/ExtendedCliParserTest.java
new file mode 100644
index 0000000..1a23912
--- /dev/null
+++ 
b/backend/manager/modules/utils/src/test/java/org/ovirt/engine/core/utils/cli/ExtendedCliParserTest.java
@@ -0,0 +1,271 @@
+package org.ovirt.engine.core.utils.cli;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.ovirt.engine.core.utils.cli.ExtendedCliParser.VALUE_SEP_LONG;
+
+import java.util.Map;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Parsing short and long arguments with {@code ExtendedCliParser} tests
+ */
+@RunWith(JUnit4.class)
+public class ExtendedCliParserTest {
+    /**
+     * Tests parsing empty arguments
+     */
+    @Test
+    public void emptyArgs() {
+        Map<String, String> results;
+        ExtendedCliParser parser = new ExtendedCliParser();
+
+        final String[] args = {};
+
+        results = parser.parse(args);
+
+        assertNotNull(results);
+        assertTrue(results.isEmpty());
+    }
+
+    /**
+     * Tests parsing short argument without value
+     */
+    @Test
+    public void shortArgWithoutValue() {
+        Map<String, String> results;
+        ExtendedCliParser parser = new ExtendedCliParser();
+        String argName = "-h";
+
+        final String[] args = { argName };
+
+        parser.addArg(new ArgumentBuilder().shortName(argName).build());
+        results = parser.parse(args);
+
+        assertNotNull(results);
+        assertFalse(results.isEmpty());
+
+        assertTrue(results.containsKey(argName));
+        assertNull(results.get(argName));
+    }
+
+    /**
+     * Tests parsing short argument with value
+     */
+    @Test
+    public void shortArgWithValue() {
+        Map<String, String> results;
+        ExtendedCliParser parser = new ExtendedCliParser();
+        String argName = "-f";
+        String argValue = "/tmp/xxx.txt";
+
+        final String[] args = { argName, argValue };
+
+        parser.addArg(new ArgumentBuilder().shortName(argName).build());
+        results = parser.parse(args);
+
+        assertNotNull(results);
+        assertFalse(results.isEmpty());
+
+        assertTrue(results.containsKey(argName));
+        assertEquals(argValue, results.get(argName));
+    }
+
+    /**
+     * Tests parsing long argument without value
+     */
+    @Test
+    public void longArgWithoutValue() {
+        Map<String, String> results;
+        ExtendedCliParser parser = new ExtendedCliParser();
+        String argName = "--help";
+
+        final String[] args = { argName };
+
+        parser.addArg(new ArgumentBuilder().longName(argName).build());
+        results = parser.parse(args);
+
+        assertNotNull(results);
+        assertFalse(results.isEmpty());
+
+        assertTrue(results.containsKey(argName));
+        assertNull(results.get(argName));
+    }
+
+    /**
+     * Tests parsing long argument with value
+     */
+    @Test
+    public void longArgWithValue() {
+        Map<String, String> results;
+        ExtendedCliParser parser = new ExtendedCliParser();
+        String argName = "--file";
+        String argValue = "/tmp/xxx.txt";
+
+        final String[] args = { argName + VALUE_SEP_LONG + argValue };
+
+        parser.addArg(new ArgumentBuilder().longName(argName).build());
+        results = parser.parse(args);
+
+        assertNotNull(results);
+        assertFalse(results.isEmpty());
+
+        assertTrue(results.containsKey(argName));
+        assertEquals(argValue, results.get(argName));
+    }
+
+    /**
+     * Tests parsing short argument with value delimited by long argument 
value separator
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void shortArgWithLongValueSep() {
+        ExtendedCliParser parser = new ExtendedCliParser();
+        String argName = "-f";
+        String argValue = "/tmp/xxx.txt";
+
+        final String[] args = { argName + VALUE_SEP_LONG + argValue };
+
+        parser.addArg(new ArgumentBuilder().shortName(argName).build());
+        parser.parse(args);
+    }
+
+    /**
+     * Tests parsing long argument with value delimited by short argument 
value separator
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void longArgWithShortValueSep() {
+        ExtendedCliParser parser = new ExtendedCliParser();
+        String argName = "--file";
+        String argValue = "/tmp/xxx.txt";
+
+        final String[] args = { argName, argValue };
+
+        parser.addArg(new ArgumentBuilder().longName(argName).build());
+        parser.parse(args);
+    }
+
+    /**
+     * Tries to parse argument with specified invalid name
+     *
+     * @param name
+     *            invalid argument name
+     */
+    protected void invalidArgName(String name) {
+        try {
+            ExtendedCliParser parser = new ExtendedCliParser();
+            parser.parse(new String[] {name});
+            fail("IllegalArgumentException expected for '" + name + "' 
argument!");
+        } catch (IllegalArgumentException ex) {
+        }
+    }
+
+    /**
+     * Tests arguments with invalid names
+     */
+    @Test
+    public void invalidArgName() {
+        invalidArgName("\t ");
+        invalidArgName("A");
+        invalidArgName("- ");
+        invalidArgName("-test");
+        invalidArgName("--");
+        invalidArgName("--?");
+        invalidArgName("--force=");
+    }
+
+    /**
+     * Tests parsing argument only in selected range
+     */
+    @Test
+    public void parseArgsInRange() {
+        Map<String, String> results;
+        ExtendedCliParser parser = new ExtendedCliParser();
+        String argName1 = "--help";
+        String argName2 = "-f";
+        String argName3 = "--output";
+        String argValue3 = "/dev/null";
+        String argName4 = "-u";
+        String argValue4 = "root";
+
+        final String[] args = {
+                argName1,
+                argName2,
+                argName3 + VALUE_SEP_LONG + argValue3,
+                argName4,
+                argValue4
+        };
+
+        parser.addArg(new ArgumentBuilder().shortName(argName2).build());
+        parser.addArg(new ArgumentBuilder().longName(argName3).build());
+        results = parser.parse(args, 1, 3);
+
+        assertNotNull(results);
+        assertFalse(results.isEmpty());
+
+        assertTrue(results.containsKey(argName2));
+
+        assertTrue(results.containsKey(argName3));
+        assertEquals(argValue3, results.get(argName3));
+    }
+
+    /**
+     * Tests parsing argument with missing required value
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void parseArgWithMissingRequiredValue() {
+        ExtendedCliParser parser = new ExtendedCliParser();
+        String argName = "-f";
+
+        final String[] args = { argName };
+
+        parser.addArg(new 
ArgumentBuilder().shortName(argName).valueRequied(true).build());
+        parser.parse(args);
+    }
+
+    /**
+     * Tests adding two arguments with the same short name
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void twoArgsWithSameShortName() {
+        ExtendedCliParser parser = new ExtendedCliParser();
+
+        parser.addArg(new ArgumentBuilder()
+                .shortName("-a")
+                .longName("--aa")
+                .valueRequied(true)
+                .build());
+
+        parser.addArg(new ArgumentBuilder()
+                .shortName("-a")
+                .longName("--bb")
+                .valueRequied(true)
+                .build());
+    }
+
+    /**
+     * Tests adding two arguments with the same long name
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void twoArgsWithSameLongName() {
+        ExtendedCliParser parser = new ExtendedCliParser();
+
+        parser.addArg(new ArgumentBuilder()
+                .shortName("-a")
+                .longName("--aa")
+                .valueRequied(true)
+                .build());
+
+        parser.addArg(new ArgumentBuilder()
+                .shortName("-b")
+                .longName("--aa")
+                .valueRequied(true)
+                .build());
+    }
+}


-- 
To view, visit http://gerrit.ovirt.org/23995
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Id7fe3bf761bd26c86d684ad1dc85751d4492239b
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: ovirt-engine-3.4
Gerrit-Owner: Martin Peřina <mper...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to