diff --git a/Dockerfile b/Dockerfile index a0bd1782..14dd7087 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ ADD setup.py requirements.txt /opt/atomicapp/ # lets install pip, and gcc for the native extensions # and remove all after use RUN yum -y install epel-release && \ - yum install -y --setopt=tsflags=nodocs python-pip python-setuptools docker gcc && \ + yum install -y --setopt=tsflags=nodocs GitPython python-pip python-setuptools docker gcc && \ python setup.py install && \ yum remove -y gcc cpp glibc-devel glibc-headers kernel-headers libmpc mpfr python-pip && \ yum clean all diff --git a/atomicapp/cli/main.py b/atomicapp/cli/main.py index e8ccce98..06d737d0 100644 --- a/atomicapp/cli/main.py +++ b/atomicapp/cli/main.py @@ -36,6 +36,7 @@ from atomicapp.nulecule import NuleculeManager from atomicapp.nulecule.exceptions import NuleculeException from atomicapp.utils import Utils +from atomicapp.index import Index logger = logging.getLogger(__name__) @@ -92,6 +93,15 @@ def cli_stop(args): logger.error(e, exc_info=True) sys.exit(1) +def cli_index(args): + argdict = args.__dict__ + i = Index(argdict["dryrun"]) + if argdict["index_action"] == "generate": + i.generate(argdict["location"]) + elif argdict["index_action"] == "list": + i.list() + elif argdict["index_action"] == "info": + i.info(argdict["app_id"]) class CLI(): @@ -240,6 +250,31 @@ def set_arguments(self): parser_stop.set_defaults(func=cli_stop) + parser_index = subparsers.add_parser("index") + index_parsers = parser_index.add_subparsers(dest="index_action") + + index_generate = index_parsers.add_parser("generate") + index_generate.add_argument( + "location", + help=( + "Path or Git repository link containing Nulecule applications " + "which will be part of the genrated index")) + index_generate.set_defaults(func=cli_index) + + index_list = index_parsers.add_parser("list") + index_list.add_argument( + "--format", + help=("Blah")) + index_list.set_defaults(func=cli_index) + + index_info = index_parsers.add_parser("info") + index_info.add_argument( + "app_id", + help=("Id of an application listed in index.")) + index_info.set_defaults(func=cli_index) + + + def run(self): self.set_arguments() args = self.parser.parse_args() @@ -252,7 +287,7 @@ def run(self): lock = LockFile(os.path.join(Utils.getRoot(), LOCK_FILE)) try: - lock.acquire(timeout=-1) + #lock.acquire(timeout=-1) args.func(args) except AttributeError: if hasattr(args, 'func'): diff --git a/atomicapp/constants.py b/atomicapp/constants.py index 95652e65..54ed004e 100644 --- a/atomicapp/constants.py +++ b/atomicapp/constants.py @@ -55,3 +55,4 @@ } } PROVIDER_CONFIG_KEY = "providerconfig" +DEFAULT_INDEX_IMAGE = "nulecule/index" diff --git a/atomicapp/index.py b/atomicapp/index.py new file mode 100644 index 00000000..60ff82e7 --- /dev/null +++ b/atomicapp/index.py @@ -0,0 +1,137 @@ +""" + Copyright 2015 Red Hat, Inc. + + This file is part of Atomic App. + + Atomic App is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Atomic App is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Atomic App. If not, see . +""" + +# Based on https://github.com/DBuildService/dock/blob/master/dock/plugin.py + +from __future__ import print_function +import os + +import imp + +import logging +from utils import Utils +from constants import DEFAULT_INDEX_IMAGE +from nulecule.base import Nulecule +from nulecule.container import DockerHandler + +from git import Repo +import tempfile +from copy import deepcopy + + +import anymarkup + +logger = logging.getLogger(__name__) + + +class Index(object): + index_template = {"location": "", "nulecules": []} + + def __init__(self, dryrun=False): + self.dryrun = dryrun + self.index = deepcopy(self.index_template) + self._load_index_file() + + def generate(self, location): + self.index = deepcopy(self.index_template) + if not os.path.exists(location): + location = self._get_repo(location) + + if not os.path.isdir(location): + raise Exception("Location has to be a directory") + + for f in os.listdir(location): + nulecule_dir = os.path.join(location, f) + if f.startswith("."): + continue + if os.path.isdir(nulecule_dir): + index_info = self._nulecule_get_info(nulecule_dir) + index_info["path"] = f + self.index["nulecules"].append(index_info) + + if len(index_info) > 0: + anymarkup.serialize_file(self.index, "gen_index.yaml", format="yaml") + + def fetch(self, index_image=DEFAULT_INDEX_IMAGE): + dh = DockerHandler(self.dryrun) + dh.pull(index_image) + dh.extract(index_image, "/gen_index.yaml", ".") + + def list(self): + for entry in self.index["nulecules"]: + print(("{}{:>%s} {}" % (50-len(entry["metadata"]["name"]))).format(entry["metadata"]["name"], entry["id"], entry["metadata"]["appversion"])) + + def info(self, app_id): + + entry = self._get_entry(app_id) + if entry: + self._print_entry(entry) + + def _nulecule_get_info(self, nulecule_dir): + index_info = {} + nulecule = Nulecule.load_from_path( + nulecule_dir, nodeps=True, dryrun=self.dryrun) + index_info["id"] = nulecule.id + index_info["metadata"] = nulecule.metadata + index_info["specversion"] = nulecule.specversion + + providers_set = set() + for component in nulecule.components: + if component.artifacts: + if len(providers_set) == 0: + providers_set = set(component.artifacts.keys()) + else: + providers_set = providers_set.intersection(set(component.artifacts.keys())) + print(providers_set) + + index_info["providers"] = list(providers_set) + return index_info + + def _get_entry(self, app_id): + for entry in self.index["nulecules"]: + if entry["id"] == app_id: + return entry + return None + + def _print_entry(self, entry, tab=""): + for key, val in entry.iteritems(): + if type(val) == dict: + print("%s%s:" % (tab,key)) + self._print_entry(val, tab+" ") + elif type(val) == list: + print("%s%s: %s" % (tab, key, ", ".join(val))) + else: + print("%s%s: %s" % (tab, key, val)) + + if entry.get("path"): + print("\n\nInclude as a graph component:\n\n" + "- name: %s\n" + " source: docker://%s/%s" % (entry["id"], "projectatomic", entry["path"])) + + def _load_index_file(self, index_file="gen_index.yaml"): + if os.path.exists(index_file): + self.index = anymarkup.parse_file(index_file) + else: + logger.warning("Couldn't load index file %s", index_file) + + def _get_repo(self, git_link): + tmp = tempfile.mkdtemp(prefix="atomicapp-index-XXXXXX") + self.index["location"] = git_link + repo = Repo.clone_from(git_link, tmp) + return tmp