1import sys
2import re
3import os
4import subprocess
5import argparse
6
7import portage.dep as portage_dep
8
9template = """import info
10
11
12class subinfo(info.infoclass):
13    def setTargets(self):
14        self.versionInfo.setDefaultValues()
15
16        self.description = "%(appname)s"
17
18    def setDependencies(self):
19        self.runtimeDependencies["virtual/base"] = "default"
20%(qtdeps)s
21%(frameworksdeps)s
22%(kdeappsdeps)s
23%(otherdeps)s
24
25from Package.CMakePackageBase import *
26
27
28class Package(CMakePackageBase):
29    def __init__(self):
30        CMakePackageBase.__init__(self)
31"""
32
33def process(app, appname, portage, craft, indent):
34    print("%sProcessing %s" % (indent, app))
35    ebuild = "%s-17.08.1.ebuild" % app
36    qtdeps = []
37    frameworksdeps = []
38    kdeappsdeps = []
39    otherdeps = []
40    qtre = re.compile("\$\(add_qt_dep ([^)]+)\)")
41    frameworksre = re.compile("\$\(add_frameworks_dep ([^)]+)\)")
42    kdeappsre = re.compile("\$\(add_kdeapps_dep ([^)]+)\)")
43    optionalre = re.compile("^[^\?]+\?")
44
45    with open(os.path.join(portage, app, ebuild), 'r') as ebuildfile:
46        allfile = ebuildfile.read()
47        dependencies = re.search("DEPEND=\"[^\"]*\"", allfile)
48
49        if dependencies:
50            deplines = dependencies.group(0).split("\n")
51
52            del deplines[0] # The first one is always spurious
53            del deplines[-1] # The last one is always spurious
54
55            for d in deplines:
56                depline = d.strip()
57                qtmatch = qtre.match(depline)
58                frameworksmatch = frameworksre.match(depline)
59                kdeappsmatch = kdeappsre.match(depline)
60
61                if qtmatch:
62                    qtdeps.append(qtmatch.group(1))
63                elif frameworksmatch:
64                    frameworksdeps.append(frameworksmatch.group(1))
65                elif kdeappsmatch:
66                    appname = kdeappsmatch.group(1)
67
68                    with subprocess.Popen(["find", os.path.join(craft, "kde", "applications"), "-name", appname], stdout=subprocess.PIPE) as find:
69                        craftdep = find.stdout.read().decode("utf-8").strip()
70
71                    if len(craftdep) == 0:
72                        if not process(appname, appname, portage, craft, "%s\t" % indent):
73                            print("%sCould not add application %s, skipping" % (indent, appname))
74
75                            return False
76
77                    kdeappsdeps.append(appname)
78                elif optionalre.match(depline):
79                    print("%sOptional dep %s" % (indent, depline))
80                else:
81                    if portage_dep.isvalidatom(depline):
82                        packagename = portage_dep.dep_getkey(depline).split("/")[1]
83
84                        # TODO be smart about these types of mappings
85                        if packagename == "eigen":
86                            packagename = "eigen3"
87
88                        with subprocess.Popen(["find", craft, "-name", packagename], stdout=subprocess.PIPE) as find:
89                            craftdep = find.stdout.read().decode("utf-8").strip()
90
91                            if len(craftdep) > 0:
92                                otherdeps.append(craftdep[len(craft):])
93                            else:
94                                print("%sDependency %s not found, skipping" % (indent, packagename))
95                                return False
96                    else:
97                        print("%sGarbage: %s" % (indent,depline))
98
99    fixedframeworks = []
100
101    for f in frameworksdeps:
102        with subprocess.Popen(["find", craft, "-name", f], stdout=subprocess.PIPE) as find:
103            fixedframeworks.append(find.stdout.read().decode("utf-8").strip()[len(craft):])
104
105    qtdepsstr = "\n".join(["        self.runtimeDependencies[\"libs/qt5/%s\"] = \"default\"" % q for q in qtdeps])
106    frameworksdepsstr = "\n".join(["        self.runtimeDependencies[\"%s\"] = \"default\"" % f for f in fixedframeworks])
107    kdeappsdepsstr = "\n".join(["        self.runtimeDependencies[\"kde/applications/%s\"] = \"default\"" % k for k in kdeappsdeps])
108    otherdepsstr = "\n".join(["        self.runtimeDependencies[\"%s\"] = \"default\"" % o for o in otherdeps])
109    recipe = template % { "appname" : appname, "qtdeps" : qtdepsstr, "frameworksdeps" : frameworksdepsstr, "otherdeps" : otherdepsstr }
110    outdir = os.path.join(craft, "kde", "applications", app)
111
112    os.mkdir(outdir)
113
114    with open(os.path.join(outdir, "%s.py" % app), 'w') as out:
115        out.write(recipe)
116
117    return True
118
119if __name__ == "__main__":
120    parser = argparse.ArgumentParser(description="Translate from portage ebuilds to craft recipes")
121
122    parser.add_argument("applist", help="List of applications to translate. Each line in this file is of the form <ebuild name> <application name>", type=argparse.FileType('r'))
123    parser.add_argument("craft", help="Location of the craft root")
124    parser.add_argument("--portage", help="Location of the portage ebuilds for KDE (defaults to /usr/portage/kde-apps)", default="/usr/portage/kde-apps")
125
126    options = parser.parse_args()
127
128    for l in options.applist:
129        app, appname = tuple(l.strip().split(" "))
130        craft_dir = os.path.join(options.craft, "kde/applications/%s" % app)
131        portage_dir = os.path.join(options.portage, app)
132
133        if os.path.exists(craft_dir):
134            print("%s exists in craft, skipping" % app)
135            continue
136
137        if not os.path.exists(portage_dir):
138            print("%s does not exist in portage, skipping" % app)
139            continue
140
141        process(app, appname, options.portage, options.craft, "")
142