From 7992ae4300777dc8d49912fe29dd00afe2f4f303 Mon Sep 17 00:00:00 2001
From: Petr "Stone" Hracek <phracek@redhat.com>
Date: Apr 07 2017 13:24:34 +0000
Subject: [PATCH 1/3] First draft of rpm2module command. Witout tests.


Signed-off-by: Petr "Stone" Hracek <phracek@redhat.com>

---

diff --git a/.gitignore b/.gitignore
index 8d09458..1fbe4b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,4 +28,4 @@ pip-log.txt
 .spyderworkspace
 .cache
 
-tests/openshift-template.yml
\ No newline at end of file
+tests/openshift-template.yml
diff --git a/modularity/cli.py b/modularity/cli.py
index 6d3350b..d46cc5e 100644
--- a/modularity/cli.py
+++ b/modularity/cli.py
@@ -3,6 +3,7 @@
 
 import sys
 import argparse
+from modularity.module_generator import ModuleGenerator
 
 from modularity.oc_template import OpenShiftTemplateGenerator
 
@@ -48,3 +49,43 @@ class CliHelper(object):
         # except Exception as e:
         #   print(e)
         #    sys.exit(1)
+
+class CLIRpm2Module(object):
+    """ Class for processing data from commandline """
+
+    @staticmethod
+    def build_parser():
+        parser = argparse.ArgumentParser(description="Creates an modulesMD file.")
+        parser.add_argument(
+            "pkgs",
+            metavar='PKGS',
+            help="Specify list of packages for module.",
+        )
+        return parser
+
+    def __init__(self, args=None):
+        self.parser = CLIRpm2Module.build_parser()
+        self.args = self.parser.parse_args(args)
+
+    def __getattr__(self, name):
+        try:
+            return getattr(self.args, name)
+        except AttributeError:
+            return object.__getattribute__(self, name)
+
+
+class CliRpm2ModuleHelper(object):
+
+    @staticmethod
+    def run():
+        try:
+            cli = CLIRpm2Module(sys.argv[1:])
+            mg = ModuleGenerator(cli)
+            mg.run()
+
+        except KeyboardInterrupt:
+            print('\nInterrupted by user')
+        # except Exception as e:
+        #   print(e)
+        #    sys.exit(1)
+
diff --git a/modularity/module_generator.py b/modularity/module_generator.py
new file mode 100644
index 0000000..4dd855e
--- /dev/null
+++ b/modularity/module_generator.py
@@ -0,0 +1,170 @@
+#!/bin/python
+
+import os
+import yaml
+import urllib
+import subprocess
+import re
+
+MODULE_TMPL = "template.yaml"
+
+
+class ModuleGenerator(object):
+
+    gen_core_list = "gen_core_binary_pkgs.txt"
+    spec_url = "http://pkgs.fedoraproject.org/cgit/rpms/%s.git/plain/%s"
+    gen_core_url = "https://raw.githubusercontent.com/asamalik/fake-base-runtime-module-image/" \
+                   "master/packages/gen-core-binary-pkgs.txt"
+
+    def __init__(self, args):
+        self.module_yaml = None
+        self.args = args
+        self.package_list = None
+        self.spec_data = {}
+
+    def _save_template(self):
+        """
+        Function saves modulemd file to the current directory
+        based on argument name
+        :return:
+        """
+        file_name = self.args.pkgs + '.yaml'
+        with open(file_name, 'w') as f:
+            try:
+                yaml.dump(self.module_yaml, f, default_flow_style=False)
+            except yaml.YAMLError as exc:
+                print(exc)
+                raise
+        print('Modulemd file is generated here ./%s' % file_name)
+        return True
+
+    def _load_template(self):
+        """
+        Function loads modulmd template
+        :return:
+        """
+        if not os.path.exists(MODULE_TMPL):
+            return False
+        with open(MODULE_TMPL, 'r') as f:
+            try:
+                self.module_yaml = yaml.load(f)
+            except yaml.YAMLError as exc:
+                print(exc)
+                raise
+        return True
+
+    @staticmethod
+    def download_file(url, filename):
+        """
+        Function checks if file exists and if not download them
+        :param url: URL of file to download
+        :param filename: downloaded filename
+        :return:
+        """
+        if not os.path.exists(filename):
+            gen_core_list = urllib.URLopener()
+            gen_core_list.retrieve(url, filename)
+
+    def _load_gen_core_list(self):
+        """
+        Function parses gen_core_list
+        :return: list of gen_core_packages
+        """
+        ModuleGenerator.download_file(self.gen_core_url,
+                                      self.gen_core_list)
+        with open(self.gen_core_list, "r") as f:
+            try:
+                self.package_list = [l.strip('\n') for l in f.readlines()]
+            except IOError:
+                raise
+
+    @staticmethod
+    def run_command(cmd):
+        """
+        Function runs command
+        :param cmd: Command to run
+        :return: output, error
+        """
+        process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
+        output, error = process.communicate()
+        return output, error
+
+    def _get_list_deps(self):
+        """
+        Function gets dependencies for specific package which is defined as a argument.
+        Dependencies are filter out agains gen_core_list.txt file
+        :return: list of dependencies
+        """
+        deps_list = []
+        cmd = 'repoquery --requires --recursive --resolve --qf %{SOURCERPM} ' + self.args.pkgs
+        output, error = ModuleGenerator.run_command(cmd)
+
+        output = [re.sub("-[^-]*-[^-]*$", "", l) for l in output.split('\n') if l]
+        for out in output:
+            if out not in self.package_list and out not in deps_list:
+                deps_list.append(out)
+        print('List of generated dependencies:\n%s' % '\n'.join(deps_list))
+        return deps_list
+
+    def _update_module_md(self, deps_list):
+        """
+        Function updates modulemd file with dependencies
+        are information taken from SPEC file.
+        :param deps_list: List of dependencies
+        :return:
+        """
+        yaml_data = self.module_yaml['data']
+        if deps_list:
+
+            if not yaml_data['components']['rpms']:
+                yaml_data['components']['rpms'] = {}
+            comp_rpms = yaml_data['components']['rpms']
+            for pkg in deps_list:
+                deps_dict = {'rationale': 'build dependency',
+                             'ref': 'f25'}
+                comp_rpms[pkg] = deps_dict
+        yaml_data['version'] = self.spec_data['Version'].strip()
+        yaml_data['summary'] = self.spec_data['Summary'].strip()
+        yaml_data['description'] = self.spec_data['Summary'].strip()
+        yaml_data['license']['module'] = self.spec_data['License'].strip()
+
+    @staticmethod
+    def parse_spec_data(data):
+        """
+        Function parses SPEC file for specific fields.
+        :param data: SPEC file data
+        :return: dictionary with parsed data
+        """
+        required_fields = ['Version', 'Summary', 'License', 'Name', 'Url']
+        # select only import RPM data
+        spec_data = [d.split(':') for d in data for field in required_fields if d.startswith(field)]
+        # Create a dictionary
+        return dict(item for item in spec_data)
+
+    def _get_rpm_stuff(self):
+        """
+        Function gets RPM stuff from SPEC file.
+        :return:
+        """
+        spec_file = self.args.pkgs + '.spec'
+        spec_url = self.spec_url % (self.args.pkgs, spec_file)
+        ModuleGenerator.download_file(spec_url, spec_file)
+        cmd = "rpmspec -P %s" % spec_file
+        output, error = ModuleGenerator.run_command(cmd)
+        if error is None:
+            with open(spec_file, "r") as f:
+                try:
+                    lines = (line.strip() for line in f)
+                    lines = list(line for line in lines if line)  # Non-blank lines in a list
+                    if lines:
+                        self.spec_data = ModuleGenerator.parse_spec_data(lines)
+                except IOError:
+                    raise
+
+    def run(self):
+        self._load_gen_core_list()
+        self._load_template()
+        self._get_rpm_stuff()
+        self._update_module_md(self._get_list_deps())
+        self._save_template()
+
diff --git a/rpm2module.py b/rpm2module.py
new file mode 100755
index 0000000..098cbad
--- /dev/null
+++ b/rpm2module.py
@@ -0,0 +1,7 @@
+#!/bin/python
+
+import sys
+from modularity.cli import CliRpm2ModuleHelper
+
+if __name__ == "__main__":
+    sys.exit(CliRpm2ModuleHelper.run())
diff --git a/template.yaml b/template.yaml
new file mode 100644
index 0000000..4837e38
--- /dev/null
+++ b/template.yaml
@@ -0,0 +1,25 @@
+document: modulemd
+version: 1
+data:
+    summary:
+    description:
+    license:
+        module:
+    dependencies:
+        buildrequires:
+            base_runtime: master
+        requires:
+            base_runtime: master
+    references:
+        community: https://fedoraproject.org/wiki/Modularity
+        documentation: https://fedoraproject.org/wiki/Fedora_Packaging_Guidelines_for_Modules
+        tracker:
+    profiles:
+        default:
+            rpms:
+        minimal:
+            rpms:
+    api:
+        rpms:
+    components:
+        rpms:

From ec15077457ab80f36975c62e2815996231fb7b38 Mon Sep 17 00:00:00 2001
From: Dominika Hodovska <dhodovsk@redhat.com>
Date: Apr 07 2017 13:24:34 +0000
Subject: [PATCH 2/3] Use brt_dep_solver.sh, modulemd lib and dnf info


---

diff --git a/modularity/module_generator.py b/modularity/module_generator.py
index 4dd855e..060f0db 100644
--- a/modularity/module_generator.py
+++ b/modularity/module_generator.py
@@ -1,170 +1,85 @@
-#!/bin/python
-
 import os
-import yaml
-import urllib
 import subprocess
-import re
-
-MODULE_TMPL = "template.yaml"
+import modulemd
+import dnf
 
 
 class ModuleGenerator(object):
 
-    gen_core_list = "gen_core_binary_pkgs.txt"
-    spec_url = "http://pkgs.fedoraproject.org/cgit/rpms/%s.git/plain/%s"
-    gen_core_url = "https://raw.githubusercontent.com/asamalik/fake-base-runtime-module-image/" \
-                   "master/packages/gen-core-binary-pkgs.txt"
-
     def __init__(self, args):
-        self.module_yaml = None
         self.args = args
-        self.package_list = None
-        self.spec_data = {}
+        self.pkg = None
+        self.mmd = modulemd.ModuleMetadata()
 
-    def _save_template(self):
+    def _save_module_md(self):
         """
         Function saves modulemd file to the current directory
         based on argument name
         :return:
         """
         file_name = self.args.pkgs + '.yaml'
-        with open(file_name, 'w') as f:
-            try:
-                yaml.dump(self.module_yaml, f, default_flow_style=False)
-            except yaml.YAMLError as exc:
-                print(exc)
-                raise
+        self.mmd.dump(file_name)
         print('Modulemd file is generated here ./%s' % file_name)
         return True
 
-    def _load_template(self):
+    def _update_module_md(self):
         """
-        Function loads modulmd template
+        Function updates modulemd file with dependencies
+        are information taken from SPEC file.
         :return:
         """
-        if not os.path.exists(MODULE_TMPL):
-            return False
-        with open(MODULE_TMPL, 'r') as f:
-            try:
-                self.module_yaml = yaml.load(f)
-            except yaml.YAMLError as exc:
-                print(exc)
-                raise
-        return True
 
-    @staticmethod
-    def download_file(url, filename):
-        """
-        Function checks if file exists and if not download them
-        :param url: URL of file to download
-        :param filename: downloaded filename
-        :return:
-        """
-        if not os.path.exists(filename):
-            gen_core_list = urllib.URLopener()
-            gen_core_list.retrieve(url, filename)
+        self.mmd.summary = str(self.pkg.summary)
+        self.mmd.description = str(self.pkg.description)
+        self.mmd.add_module_license(str(self.pkg.license))
 
-    def _load_gen_core_list(self):
-        """
-        Function parses gen_core_list
-        :return: list of gen_core_packages
-        """
-        ModuleGenerator.download_file(self.gen_core_url,
-                                      self.gen_core_list)
-        with open(self.gen_core_list, "r") as f:
-            try:
-                self.package_list = [l.strip('\n') for l in f.readlines()]
-            except IOError:
-                raise
-
-    @staticmethod
-    def run_command(cmd):
-        """
-        Function runs command
-        :param cmd: Command to run
-        :return: output, error
-        """
-        process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
-        output, error = process.communicate()
-        return output, error
+        for pkg in self.build_deps.intersection(self.run_deps):
+            self.mmd.components.add_rpm(pkg, "Build and runtime dependency.")
 
-    def _get_list_deps(self):
-        """
-        Function gets dependencies for specific package which is defined as a argument.
-        Dependencies are filter out agains gen_core_list.txt file
-        :return: list of dependencies
-        """
-        deps_list = []
-        cmd = 'repoquery --requires --recursive --resolve --qf %{SOURCERPM} ' + self.args.pkgs
-        output, error = ModuleGenerator.run_command(cmd)
-
-        output = [re.sub("-[^-]*-[^-]*$", "", l) for l in output.split('\n') if l]
-        for out in output:
-            if out not in self.package_list and out not in deps_list:
-                deps_list.append(out)
-        print('List of generated dependencies:\n%s' % '\n'.join(deps_list))
-        return deps_list
-
-    def _update_module_md(self, deps_list):
-        """
-        Function updates modulemd file with dependencies
-        are information taken from SPEC file.
-        :param deps_list: List of dependencies
-        :return:
-        """
-        yaml_data = self.module_yaml['data']
-        if deps_list:
-
-            if not yaml_data['components']['rpms']:
-                yaml_data['components']['rpms'] = {}
-            comp_rpms = yaml_data['components']['rpms']
-            for pkg in deps_list:
-                deps_dict = {'rationale': 'build dependency',
-                             'ref': 'f25'}
-                comp_rpms[pkg] = deps_dict
-        yaml_data['version'] = self.spec_data['Version'].strip()
-        yaml_data['summary'] = self.spec_data['Summary'].strip()
-        yaml_data['description'] = self.spec_data['Summary'].strip()
-        yaml_data['license']['module'] = self.spec_data['License'].strip()
-
-    @staticmethod
-    def parse_spec_data(data):
-        """
-        Function parses SPEC file for specific fields.
-        :param data: SPEC file data
-        :return: dictionary with parsed data
-        """
-        required_fields = ['Version', 'Summary', 'License', 'Name', 'Url']
-        # select only import RPM data
-        spec_data = [d.split(':') for d in data for field in required_fields if d.startswith(field)]
-        # Create a dictionary
-        return dict(item for item in spec_data)
+        for pkg in (self.build_deps - self.run_deps):
+            self.mmd.components.add_rpm(pkg, "Build dependency.")
 
-    def _get_rpm_stuff(self):
+        for pkg in (self.run_deps - self.build_deps):
+            self.mmd.components.add_rpm(pkg, "Runtime dependency.")
+
+    def _get_pkg_info(self):
         """
-        Function gets RPM stuff from SPEC file.
-        :return:
+            Function loads package from dnf
+            :return:
+            """
+        b = dnf.Base()
+        b.read_all_repos()
+        b.fill_sack()
+
+        q = b.sack.query().filter(name=self.args.pkgs, reponame='fedora', latest=True)
+
+        if len(q) > 1:
+            raise ValueError('Name of package is not unique')
+        if len(q) == 0:
+            raise ValueError('No package found in repo')
+        self.pkg = q[0]
+
+    def _get_dependencies(self):
         """
-        spec_file = self.args.pkgs + '.spec'
-        spec_url = self.spec_url % (self.args.pkgs, spec_file)
-        ModuleGenerator.download_file(spec_url, spec_file)
-        cmd = "rpmspec -P %s" % spec_file
-        output, error = ModuleGenerator.run_command(cmd)
-        if error is None:
-            with open(spec_file, "r") as f:
-                try:
-                    lines = (line.strip() for line in f)
-                    lines = list(line for line in lines if line)  # Non-blank lines in a list
-                    if lines:
-                        self.spec_data = ModuleGenerator.parse_spec_data(lines)
-                except IOError:
-                    raise
+            Function gets build and runtime dependencies of package
+            :return:
+            """
+        subprocess.call(['/bin/bash', './brt_dep_solver.sh', self.args.pkgs])
 
-    def run(self):
-        self._load_gen_core_list()
-        self._load_template()
-        self._get_rpm_stuff()
-        self._update_module_md(self._get_list_deps())
-        self._save_template()
+        self.build_deps_file = self.args.pkgs + '-build-deps.txt'
+        self.run_deps_file = self.args.pkgs + '-runtime-deps.txt'
 
+        if not os.path.exists(self.build_deps_file) or not os.path.exists(self.run_deps_file):
+            raise IOError("Dependency file not found.")
+
+        with open(self.build_deps_file, 'r') as f:
+            self.build_deps = set([l.strip('\n') for l in f.readlines()])
+
+        with open(self.run_deps_file, 'r') as f:
+            self.run_deps = set([l.strip('\n') for l in f.readlines()])
+
+    def run(self):
+        self._get_pkg_info()
+        self._get_dependencies()
+        self._update_module_md()
+        self._save_module_md()
diff --git a/template.yaml b/template.yaml
deleted file mode 100644
index 4837e38..0000000
--- a/template.yaml
+++ /dev/null
@@ -1,25 +0,0 @@
-document: modulemd
-version: 1
-data:
-    summary:
-    description:
-    license:
-        module:
-    dependencies:
-        buildrequires:
-            base_runtime: master
-        requires:
-            base_runtime: master
-    references:
-        community: https://fedoraproject.org/wiki/Modularity
-        documentation: https://fedoraproject.org/wiki/Fedora_Packaging_Guidelines_for_Modules
-        tracker:
-    profiles:
-        default:
-            rpms:
-        minimal:
-            rpms:
-    api:
-        rpms:
-    components:
-        rpms:

From 807c11a7388a365a6748c287397a81781a5db4f0 Mon Sep 17 00:00:00 2001
From: Dominika Hodovska <dhodovsk@redhat.com>
Date: Apr 10 2017 12:27:02 +0000
Subject: [PATCH 3/3] Allow non-existence of deps files


---

diff --git a/modularity/module_generator.py b/modularity/module_generator.py
index 060f0db..0a70669 100644
--- a/modularity/module_generator.py
+++ b/modularity/module_generator.py
@@ -10,6 +10,8 @@ class ModuleGenerator(object):
         self.args = args
         self.pkg = None
         self.mmd = modulemd.ModuleMetadata()
+        self.build_deps = set()
+        self.run_deps = set()
 
     def _save_module_md(self):
         """
@@ -69,14 +71,13 @@ class ModuleGenerator(object):
         self.build_deps_file = self.args.pkgs + '-build-deps.txt'
         self.run_deps_file = self.args.pkgs + '-runtime-deps.txt'
 
-        if not os.path.exists(self.build_deps_file) or not os.path.exists(self.run_deps_file):
-            raise IOError("Dependency file not found.")
+        if os.path.exists(self.build_deps_file):
+            with open(self.build_deps_file, 'r') as f:
+                self.build_deps = set([l.strip('\n') for l in f.readlines()])
 
-        with open(self.build_deps_file, 'r') as f:
-            self.build_deps = set([l.strip('\n') for l in f.readlines()])
-
-        with open(self.run_deps_file, 'r') as f:
-            self.run_deps = set([l.strip('\n') for l in f.readlines()])
+        if os.path.exists(self.run_deps_file):
+            with open(self.run_deps_file, 'r') as f:
+                self.run_deps = set([l.strip('\n') for l in f.readlines()])
 
     def run(self):
         self._get_pkg_info()

