    :search-strat "breadth-first"
    })
 
-(def subcommand-cli
-  {"display-config"
+(def available-option-packs
+  {
+   "multi-version-mode"
    {
-    :description "Print the effective combined configuration (and arguments) of all the given config files."
-    :function display-config!
+    :conflict-strat "inclusive"
+    :resolve-strat "fast"
+    :alternatives false
     }
-   "generate-card"
+    "firstfound-version-mode"
    {
-    :description "Generate dscard file based on arguments given"
-    :function generate-card!
-    :required-arguments {:id ["-i" "--id"]
-                         :version ["-v" "--version"]
-                         :location ["-l" "--location"]}
-    :cli [
-          ["-C" "--card-file FILE"
-           "The name of the card file"
-           :default nil
-           :default-desc (str (:card-file subcommand-option-defaults))
-           :validate [#(not (empty? %))
-                      "Out file must not be empty."]]
-          ["-i" "--id ID"
-           "ID (name) of the package"
-           :validate [#(not (empty? %))
-                      "ID must be a non-empty string."]
-           :required true]
-          ["-l" "--location LOCATION"
-           "URL or filepath of the package"
-           :validate [#(not (empty? %))
-                      "Location must be a non-empty string."]
-           :required true]
-          ["-m" "--meta K=V"
-           "Add additional metadata"
-           :validate [#(re-matches #"^[^=]+=[^=].*$" %)
-                      "Metadata must be presented as <key>=<value> pair."]
-           :id :meta
-           :assoc-fn
-           (fn [m k v]
-             (let [[_ rk rv] (re-find #"^([^=]+)=([^=].*)$" v)]
-               (update-in m [k] #(assoc % (keyword rk) rv))))]
-          ["-r" "--requirement REQ"
-           "List requirement **"
-           :validate [#(re-matches r/str-requirement-regex %)
-                      "Requirement must look like one of these: `!a`, `a`, `a|b`, a>2.0,<=3.0,!=2.5;>4.0,<=5.0`"]
-           :id :requirements
-           :assoc-fn
-           (fn [m k v] (update-in m [k] #(conj % v)))]
-          ["-v" "--version VERSION"
-           "Version of the package"
-           :validate [#(re-matches r/version-regex %)
-                      "Sorry, given argument doesn't look like a version."]
-           :required true]
-          ]}
-   "generate-repo-index"
-   {:description "Generate repository index based on degasolv package cards"
-    :function generate-repo-index-cli!
-    :cli [["-a" "--add-to INDEX"
-           "Add to repo index INDEX"]
-          ["-d" "--search-directory DIR" "Find degasolv cards here"
-           :default nil
-           :default-desc (str (:search-directory subcommand-option-defaults))
-           :validate [#(and
-                        (fs/directory? %)
-                        (fs/exists? %))
-                      "Must be a directory which exists on the file system."]]
-          ["-I" "--index-file FILE"
-           "The name of the repo file"
-           :default nil
-           :default-desc (str (:index-file subcommand-option-defaults))]
-          ["-V" "--version-comparison CMP"
-           "May be 'debian', 'maven', 'naive', 'python', 'rpm', 'rubygem', or 'semver'."
-           :default nil
-           :default-desc "maven"
-           :validate [#(some #{%} (keys version-comparators))
-                      "Version comparison must be 'debian', 'maven', 'naive', 'python', 'rubygem', or 'semver'."]]]}
-
-   "resolve-locations"
-   {:description "Print the locations of the packages which will resolve all given dependencies."
-    :function resolve-locations!
-    :required-arguments {:repositories ["-R" "--repository"]
-                         :requirements ["-r" "--requirement"]}
-    :cli [
-          ["-a" "--enable-alternatives" "Consider all alternatives (default)"
-           :assoc-fn (fn [m k v] (assoc m :alternatives true))]
-          ["-A" "--disable-alternatives" "Consider only first alternatives"
-           :assoc-fn (fn [m k v] (assoc m :alternatives false))]
-          ["-e" "--search-strat STRAT"
-           "May be 'breadth-first' or 'depth-first'."
-           :default nil
-           :default-desc (str (:search-strat subcommand-option-defaults))
-           :validate [#(or (= "breadth-first" %)
-                           (= "depth-first" %))
-                      "Search strategy must either be 'breadth-first' or 'depth-first'."]]
-          ["-g" "--enable-error-format" "Enable output format for errors"
-           :assoc-fn (fn [m k v] (assoc m :error-format true))]
-          ["-G" "--disable-error-format" "Disable output format for errors (default)"
-           :assoc-fn (fn [m k v] (assoc m :error-format false))]
-          ["-f" "--conflict-strat STRAT"
-           "May be 'exclusive', 'inclusive' or 'prioritized'."
-           :default nil
-           :default-desc (str (:conflict-strat subcommand-option-defaults))
-           :validate [#(or (= "exclusive" %)
-                           (= "inclusive" %)
-                           (= "prioritized" %))
-                      "Conflict strategy must either be 'exclusive', 'inclusive', or 'prioritized'."]]
-          ["-o" "--output-format FORMAT" "May be 'plain', 'edn' or 'json'"
-           :default nil
-           :default-desc (str (:output-format subcommand-option-defaults))
-           :validate [#(or (= "plain" %)
-                           (= "json" %)
-                           (= "edn" %))
-                      "Output format may be either be 'plain', 'edn' or 'json'"]]
-          ["-p" "--present-package PKG"
-           "Hard present package. **"
-           :id :present-packages
-           :validate
-           [#(re-matches r/str-frozen-package-regex %)
-            "Package must be specified as `<pkgname>==<pkgversion>`"]
-           :assoc-fn
-           (fn [m k v] (update-in m [k] #(conj % v)))]
-          ["-r" "--requirement REQ"
-           "Resolve req. **"
-           :id :requirements
-           :validate
-           [#(re-matches r/str-requirement-regex %)
-            "Requirement must look like one of these: `!a`, `a`, `a|b`, a>2.0,<=3.0,!=2.5;>4.0,<=5.0`"]
-           :assoc-fn
-           (fn [m k v] (update-in m [k] #(conj % v)))]
-          ["-R" "--repository INDEX"
-           "Search INDEX for packages. **"
-           :id :repositories
-           :assoc-fn
-           (fn [m k v] (update-in m [k] #(conj % v)))]
-          ["-s" "--resolve-strat STRAT"
-           "May be 'fast' or 'thorough'."
-           :default nil
-           :default-desc (str (:resolve-strat subcommand-option-defaults))
-           :validate [#(or (= "thorough" %) (= "fast" %))
-                      "Resolve strategy must either be 'thorough' or 'fast'."]]
-
-          ["-S" "--index-strat STRAT"
-           "May be 'priority' or 'global'."
-           :default nil
-           :default-desc (str (:index-strat subcommand-option-defaults))
-           :validate [#(or (= "priority" %) (= "global" %))
-                      "Strategy must either be 'priority' or 'global'."]]
-          ["-t" "--package-system SYS"
-           "May be 'degasolv' or 'apt'."
-           :default nil
-           :default-desc (str (:package-system subcommand-option-defaults))
-           :validate [#(or (= "degasolv" %) (= "apt" %))
-                      "Package system must be either 'degasolv' or 'apt'."]]
-          ["-V" "--version-comparison CMP"
-           "May be 'debian', 'maven', 'naive', 'python', 'rpm', 'rubygem', or 'semver'."
-           :default nil
-           :default-desc "maven"
-           :validate [#(some #{%} (keys version-comparators))
-                      "Version comparison must be 'debian', 'maven', 'naive', 'python', 'rubygem', or 'semver'."]]
-          ]}
-   "query-repo"
-   {:description "Query repository for a particular package"
-    :function query-repo!
-    :required-arguments {:repositories ["-R" "--repository"]
-                         :query ["-q" "--query"]}
-    :cli [
-          ["-g" "--enable-error-format" "Enable output format for errors"
-           :assoc-fn (fn [m k v] (assoc m :error-format true))]
-          ["-G" "--disable-error-format" "Disable output format for errors (default)"
-           :assoc-fn (fn [m k v] (assoc m :error-format false))]
-          ["-o" "--output-format FORMAT" "May be 'plain', 'edn' or 'json'"
-           :default nil
-           :default-desc (str (:output-format subcommand-option-defaults))
-           :validate [#(or (= "plain" %)
-                           (= "json" %)
-                           (= "edn" %))
-                      "Output format may be either be 'plain', 'edn' or 'json'"]]
-          ["-q" "--query QUERY"
-           "Display packages matching query string."
-           :validate [#(and (re-matches r/str-requirement-regex %)
-                            (let [strreq (string-to-requirement %)]
-                              (and (= (count strreq) 1)
-                                   (= (:status (get strreq 0)) :present))))
-                      "Query must look like one of these: `a`, `a`, a>2.0,<=3.0,!=2.5;>4.0,<=5.0`"]]
-          ["-R" "--repository INDEX"
-           "Search INDEX for packages. **"
-           :id :repositories
-           :assoc-fn
-           (fn [m k v] (update-in m [k] #(conj % v)))]
-          ["-S" "--index-strat STRAT"
-           "May be 'priority' or 'global'."
-           :default nil
-           :default-desc (str (:index-strat subcommand-option-defaults))
-           :validate [#(or (= "priority" %) (= "global" %))
-                      "Strategy must either be 'priority' or 'global'."]]
-          ["-t" "--package-system SYS"
-           "May be 'degasolv' or 'apt'."
-           :default nil
-           :default-desc (str (:package-system subcommand-option-defaults))
-           :validate [#(or (= "degasolv" %) (= "apt" %))
-                      "Package system must be either 'degasolv' or 'apt'."]]
-          ["-V" "--version-comparison CMP"
-           "May be 'debian', 'maven', 'naive', 'python', 'rpm', 'rubygem', or 'semver'."
-           :default nil
-           :default-desc "maven"
-           :validate [#(some #{%} (keys version-comparators))
-                      "Version comparison must be 'debian', 'maven', 'naive', 'python', 'rubygem', or 'semver'."]]
-          ]
+    :conflict-strat "prioritized"
+    :resolve-strat "fast"
+    :alternatives false
+    }
+  })
+
+(def cli-spec
+  {
+   :description "Degasolv: You love me."
+   :cli
+   [["-c" "--config-file FILE" "Config file location **"
+     :id :config-files
+     :default []
+     :default-desc "./degasolv.edn"
+     :assoc-fn
+     (fn [m k v] (update-in m [k] #(conj % v)))]
+    ["-k" "--option-pack PACK" "Specify option pack **"
+     :id :option-packs
+     :default []
+     :default-desc ""
+     :validate [#(get available-option-packs %)
+                (str
+                 "Must be one of: "
+                 (string/join "," (keys available-option-packs)))]
+     :assoc-fn
+     (fn [m k v] (update-in m [k] #(conj % v)))]]
+   :subcommands
+   {"display-config"
+    {
+     :description "Print the effective combined configuration (and arguments) of all the given config files."
+     :function display-config!
+     }
+    "generate-card"
+    {
+     :description "Generate dscard file based on arguments given"
+     :function generate-card!
+     :required-arguments {:id ["-i" "--id"]
+                          :version ["-v" "--version"]
+                          :location ["-l" "--location"]}
+     :cli [
+           ["-C" "--card-file FILE"
+            "The name of the card file"
+            :default nil
+            :default-desc (str (:card-file subcommand-option-defaults))
+            :validate [#(not (empty? %))
+                       "Out file must not be empty."]]
+           ["-i" "--id ID"
+            "ID (name) of the package"
+            :validate [#(not (empty? %))
+                       "ID must be a non-empty string."]
+            :required true]
+           ["-l" "--location LOCATION"
+            "URL or filepath of the package"
+            :validate [#(not (empty? %))
+                       "Location must be a non-empty string."]
+            :required true]
+           ["-m" "--meta K=V"
+            "Add additional metadata"
+            :validate [#(re-matches #"^[^=]+=[^=].*$" %)
+                       "Metadata must be presented as <key>=<value> pair."]
+            :id :meta
+            :assoc-fn
+            (fn [m k v]
+              (let [[_ rk rv] (re-find #"^([^=]+)=([^=].*)$" v)]
+                (update-in m [k] #(assoc % (keyword rk) rv))))]
+           ["-r" "--requirement REQ"
+            "List requirement **"
+            :validate [#(re-matches r/str-requirement-regex %)
+                       "Requirement must look like one of these: `!a`, `a`, `a|b`, a>2.0,<=3.0,!=2.5;>4.0,<=5.0`"]
+            :id :requirements
+            :assoc-fn
+            (fn [m k v] (update-in m [k] #(conj % v)))]
+           ["-v" "--version VERSION"
+            "Version of the package"
+            :validate [#(re-matches r/version-regex %)
+                       "Sorry, given argument doesn't look like a version."]
+            :required true]
+           ]}
+    "generate-repo-index"
+    {:description "Generate repository index based on degasolv package cards"
+     :function generate-repo-index-cli!
+     :cli [["-a" "--add-to INDEX"
+            "Add to repo index INDEX"]
+           ["-d" "--search-directory DIR" "Find degasolv cards here"
+            :default nil
+            :default-desc (str (:search-directory subcommand-option-defaults))
+            :validate [#(and
+                         (fs/directory? %)
+                         (fs/exists? %))
+                       "Must be a directory which exists on the file system."]]
+           ["-I" "--index-file FILE"
+            "The name of the repo file"
+            :default nil
+            :default-desc (str (:index-file subcommand-option-defaults))]
+           ["-V" "--version-comparison CMP"
+            "May be 'debian', 'maven', 'naive', 'python', 'rpm', 'rubygem', or 'semver'."
+            :default nil
+            :default-desc "maven"
+            :validate [#(some #{%} (keys version-comparators))
+                       "Version comparison must be 'debian', 'maven', 'naive', 'python', 'rubygem', or 'semver'."]]]}
+
+    "resolve-locations"
+    {:description "Print the locations of the packages which will resolve all given dependencies."
+     :function resolve-locations!
+     :required-arguments {:repositories ["-R" "--repository"]
+                          :requirements ["-r" "--requirement"]}
+     :cli [
+           ["-a" "--enable-alternatives" "Consider all alternatives (default)"
+            :assoc-fn (fn [m k v] (assoc m :alternatives true))]
+           ["-A" "--disable-alternatives" "Consider only first alternatives"
+            :assoc-fn (fn [m k v] (assoc m :alternatives false))]
+           ["-e" "--search-strat STRAT"
+            "May be 'breadth-first' or 'depth-first'."
+            :default nil
+            :default-desc (str (:search-strat subcommand-option-defaults))
+            :validate [#(or (= "breadth-first" %)
+                            (= "depth-first" %))
+                       "Search strategy must either be 'breadth-first' or 'depth-first'."]]
+           ["-g" "--enable-error-format" "Enable output format for errors"
+            :assoc-fn (fn [m k v] (assoc m :error-format true))]
+           ["-G" "--disable-error-format" "Disable output format for errors (default)"
+            :assoc-fn (fn [m k v] (assoc m :error-format false))]
+           ["-f" "--conflict-strat STRAT"
+            "May be 'exclusive', 'inclusive' or 'prioritized'."
+            :default nil
+            :default-desc (str (:conflict-strat subcommand-option-defaults))
+            :validate [#(or (= "exclusive" %)
+                            (= "inclusive" %)
+                            (= "prioritized" %))
+                       "Conflict strategy must either be 'exclusive', 'inclusive', or 'prioritized'."]]
+           ["-o" "--output-format FORMAT" "May be 'plain', 'edn' or 'json'"
+            :default nil
+            :default-desc (str (:output-format subcommand-option-defaults))
+            :validate [#(or (= "plain" %)
+                            (= "json" %)
+                            (= "edn" %))
+                       "Output format may be either be 'plain', 'edn' or 'json'"]]
+           ["-p" "--present-package PKG"
+            "Hard present package. **"
+            :id :present-packages
+            :validate
+            [#(re-matches r/str-frozen-package-regex %)
+             "Package must be specified as `<pkgname>==<pkgversion>`"]
+            :assoc-fn
+            (fn [m k v] (update-in m [k] #(conj % v)))]
+           ["-r" "--requirement REQ"
+            "Resolve req. **"
+            :id :requirements
+            :validate
+            [#(re-matches r/str-requirement-regex %)
+             "Requirement must look like one of these: `!a`, `a`, `a|b`, a>2.0,<=3.0,!=2.5;>4.0,<=5.0`"]
+            :assoc-fn
+            (fn [m k v] (update-in m [k] #(conj % v)))]
+           ["-R" "--repository INDEX"
+            "Search INDEX for packages. **"
+            :id :repositories
+            :assoc-fn
+            (fn [m k v] (update-in m [k] #(conj % v)))]
+           ["-s" "--resolve-strat STRAT"
+            "May be 'fast' or 'thorough'."
+            :default nil
+            :default-desc (str (:resolve-strat subcommand-option-defaults))
+            :validate [#(or (= "thorough" %) (= "fast" %))
+                       "Resolve strategy must either be 'thorough' or 'fast'."]]
+
+           ["-S" "--index-strat STRAT"
+            "May be 'priority' or 'global'."
+            :default nil
+            :default-desc (str (:index-strat subcommand-option-defaults))
+            :validate [#(or (= "priority" %) (= "global" %))
+                       "Strategy must either be 'priority' or 'global'."]]
+           ["-t" "--package-system SYS"
+            "May be 'degasolv' or 'apt'."
+            :default nil
+            :default-desc (str (:package-system subcommand-option-defaults))
+            :validate [#(or (= "degasolv" %) (= "apt" %))
+                       "Package system must be either 'degasolv' or 'apt'."]]
+           ["-V" "--version-comparison CMP"
+            "May be 'debian', 'maven', 'naive', 'python', 'rpm', 'rubygem', or 'semver'."
+            :default nil
+            :default-desc "maven"
+            :validate [#(some #{%} (keys version-comparators))
+                       "Version comparison must be 'debian', 'maven', 'naive', 'python', 'rubygem', or 'semver'."]]
+           ]}
+    "query-repo"
+    {:description "Query repository for a particular package"
+     :function query-repo!
+     :required-arguments {:repositories ["-R" "--repository"]
+                          :query ["-q" "--query"]}
+     :cli [
+           ["-g" "--enable-error-format" "Enable output format for errors"
+            :assoc-fn (fn [m k v] (assoc m :error-format true))]
+           ["-G" "--disable-error-format" "Disable output format for errors (default)"
+            :assoc-fn (fn [m k v] (assoc m :error-format false))]
+           ["-o" "--output-format FORMAT" "May be 'plain', 'edn' or 'json'"
+            :default nil
+            :default-desc (str (:output-format subcommand-option-defaults))
+            :validate [#(or (= "plain" %)
+                            (= "json" %)
+                            (= "edn" %))
+                       "Output format may be either be 'plain', 'edn' or 'json'"]]
+           ["-q" "--query QUERY"
+            "Display packages matching query string."
+            :validate [#(and (re-matches r/str-requirement-regex %)
+                             (let [strreq (string-to-requirement %)]
+                               (and (= (count strreq) 1)
+                                    (= (:status (get strreq 0)) :present))))
+                       "Query must look like one of these: `a`, `a`, a>2.0,<=3.0,!=2.5;>4.0,<=5.0`"]]
+           ["-R" "--repository INDEX"
+            "Search INDEX for packages. **"
+            :id :repositories
+            :assoc-fn
+            (fn [m k v] (update-in m [k] #(conj % v)))]
+           ["-S" "--index-strat STRAT"
+            "May be 'priority' or 'global'."
+            :default nil
+            :default-desc (str (:index-strat subcommand-option-defaults))
+            :validate [#(or (= "priority" %) (= "global" %))
+                       "Strategy must either be 'priority' or 'global'."]]
+           ["-t" "--package-system SYS"
+            "May be 'degasolv' or 'apt'."
+            :default nil
+            :default-desc (str (:package-system subcommand-option-defaults))
+            :validate [#(or (= "degasolv" %) (= "apt" %))
+                       "Package system must be either 'degasolv' or 'apt'."]]
+           ["-V" "--version-comparison CMP"
+            "May be 'debian', 'maven', 'naive', 'python', 'rpm', 'rubygem', or 'semver'."
+            :default nil
+            :default-desc "maven"
+            :validate [#(some #{%} (keys version-comparators))
+                       "Version comparison must be 'debian', 'maven', 'naive', 'python', 'rubygem', or 'semver'."]]
+           ]
+     }
     }
    }
   )

           "` key in the config file,")
      (str "  or use `" small-arg "` or `" large-arg "` at the command line.")])))

(def available-option-packs
  {
   "multi-version-mode"
   {
    :conflict-strat "inclusive"
    :resolve-strat "fast"
    :alternatives false
    }
    "firstfound-version-mode"
   {
    :conflict-strat "prioritized"
    :resolve-strat "fast"
    :alternatives false
    }
  })

(def cli-options
  [["-c" "--config-file FILE" "Config file location **"
    :id :config-files
    :default []
    :default-desc "./degasolv.edn"
    :assoc-fn
    (fn [m k v] (update-in m [k] #(conj % v)))]
   ["-k" "--option-pack PACK" "Specify option pack **"
    :id :option-packs
    :default []
    :default-desc ""
    :validate [#(get available-option-packs %)
               (str
                "Must be one of: "
                (string/join "," (keys available-option-packs)))]
    :assoc-fn
    (fn [m k v] (update-in m [k] #(conj % v)))]])

(defn- deep-merge [a b]
  (merge-with (fn [x y]
                (cond (map? y) (deep-merge x y)
                      (vector? y) (conj x y)
                      :else y))
              a b))

(defn get-config [configs]
  (try

               ""
               ""))

(defn usage [command-name options-summary & {:keys [sub-command]}]
  (let [display-command (if sub-command
                          sub-command
                          "<command>")]
    (->> [(str "Usage: "
               command-name
               " <options> "
               (when sub-command
                 (str
                  sub-command
                  " <"
                  sub-command
                  "-options>")))
          ""
          "Options are shown below. Default values are listed with the"
          "  descriptions. Options marked with `**` may be"
          "  used more than once."
          ""
