Warning, /packaging/kdesdk-devenv-dependencies/packages is written in an unsupported language. File is not indexed.

0001 #!/usr/bin/env python3
0002 
0003 import argparse
0004 import sys
0005 import shutil
0006 import subprocess
0007 import operator
0008 from enum import Enum
0009 from functools import reduce
0010 import concurrent.futures
0011 import json
0012 import io
0013 
0014 # for apt
0015 import urllib.request
0016 
0017 neededFiles = [
0018     "Qt5CoreConfig.cmake",
0019     "Qt5QuickConfig.cmake",
0020     "Qt5WebEngineConfig.cmake",
0021 
0022     "ECMConfig.cmake",
0023     "KF5*Config.cmake",
0024 ]
0025 
0026 neededBinaries =  [
0027     "gcc",
0028     "g++",
0029     "cmake",
0030     "cmake-gui",
0031     "git",
0032     "gdb",
0033     "clang",
0034     "make",
0035     "ninja",
0036     "msgfmt" #it's needed when including ki18n
0037     #"clazy",
0038 ]
0039 
0040 suggestedBinaries = [
0041     "plasmaengineexplorer",
0042     "plasmawindowed",
0043     "cuttlefish",
0044     "kate",
0045     "kdevelop"
0046 ]
0047 
0048 def progressCallback(progress, type, user_data):
0049     pass
0050     #print('  ', type.value_name, 'package:', progress.props.package_id, ':', progress.props.percentage, '%')
0051 
0052 class RequirementType(Enum):
0053     Needed = 0
0054     Suggested = 1
0055 
0056 class Contents:
0057     class Connection:
0058         def __init__(self, urlBase = 'https://contents.neon.kde.org/v2'):
0059             self.urlBase = urlBase
0060 
0061         def getJSON(self, path):
0062             url = "%s/%s" % (self.urlBase, path)
0063             response = urllib.request.urlopen(url)
0064             ret = json.loads(response.read().decode('utf-8'))
0065             return ret
0066 
0067     class Archive:
0068         overrides = {
0069             "usr/bin/gcc": "build-essential",
0070             "usr/bin/g++": "build-essential",
0071             "usr/bin/make": "build-essential"
0072         }
0073 
0074         def __init__(self, id):
0075             self.id = id
0076             self.connection = Contents.Connection()
0077 
0078         def findFile(self, file):
0079             return self.connection.getJSON(('findFirst/%s?q=*%s' % (self.id, file)))
0080 
0081         def findPackageForFile(self, file):
0082             try:
0083                 return self.overrides[file]
0084             except:
0085                 pass
0086             payload = self.findFile(file)
0087             if not payload:
0088                 return None
0089             assert len(payload.keys()) == 1
0090             # Nested list since we don't resolve files, simply pick first.
0091             packages = list(payload.values())[0]
0092             assert len(packages) == 1, "Cannot find which package to use for " + file
0093             return packages[0]
0094 
0095         def findAllPackages(self, file):
0096             payload = self.findFile(file)
0097             packages = payload.values()
0098             return [item for sublist in packages for item in sublist] #make sure it's just a list, not a list of lists
0099 
0100     poolsCache = None
0101 
0102     @classmethod
0103     def pools(klass, connection = Connection()):
0104         if not klass.poolsCache:
0105             klass.poolsCache = connection.getJSON('pools')
0106         return klass.poolsCache
0107 
0108 class Global:
0109     repositories = None
0110     backend = "debian"
0111 
0112     packages = {}
0113     packagesNotFound = []
0114 
0115     def __init__(self):
0116         values  = [ (v, RequirementType.Needed, False) for v in neededFiles]
0117         values += [ (v, RequirementType.Needed, True)  for v in neededBinaries]
0118         values += [ (v, RequirementType.Suggested, True)  for v in suggestedBinaries]
0119 
0120         self.process(values)
0121 
0122     def addResults(self, fileName, req, pkgs):
0123         if not pkgs:
0124             self.packagesNotFound.append(fileName)
0125         else:
0126             for p in pkgs:
0127                 self.packages[p] = (req, fileName)
0128 
0129     def printVerbose(self):
0130         if self.packagesNotFound:
0131             print("Could not find packages for", self.packagesNotFound)
0132             print()
0133 
0134         print("We suggest the following packages:")
0135         for pkg, props in self.packages.items():
0136             print("* ", pkg, "<-", props)
0137 
0138     def printPackagesJson(self):
0139         ret = {
0140             "required": [],
0141             "suggested": []
0142         }
0143         for pkg, (required, filename) in self.packages.items():
0144             if required == RequirementType.Needed:
0145                 ret["required"].append(pkg)
0146             else:
0147                 ret["suggested"].append(pkg)
0148         ret["required"].sort()
0149         ret["suggested"].sort()
0150         print(json.dumps(ret, sort_keys=True, indent=4, separators=(',', ': ')))
0151 
0152     def printPackages(self):
0153         print(" ".join(self.packages.keys()))
0154 
0155     def installPackages(self):
0156         subprocess.call(["pkcon", "install"] + list(self.packages.keys()))
0157 
0158     def searchFile(fileName, requirement, isExecutable):
0159         packages = None
0160 
0161         #ArchLinux
0162         if Global.backend == "archlinux":
0163             cmd = ["pacman", "--machinereadable", "-F", fileName]
0164             output = subprocess.check_output(cmd)
0165             process = output.split(b'\0')
0166             packages = [ process[1].decode("utf-8") ] # only use the first alternative, pacman will sort them by repository precedence
0167         #Debian
0168         elif Global.backend == "debian":
0169             prefix = "usr/bin/" if isExecutable else "/"
0170             packages = []
0171             for repo in Contents.pools():
0172                 pkg = Contents.Archive(repo).findPackageForFile(prefix + fileName)
0173                 if pkg:
0174                     packages = [pkg]
0175                     break
0176             # print("pac", fileName, package)
0177 
0178         return (fileName, requirement, packages)
0179 
0180     def searchGlobFiles(fileName, requirement, isExecutable):
0181         packages = None
0182 
0183         #ArchLinux
0184         if Global.backend == "archlinux":
0185             fileNamerx = fileName.replace("*", ".*")
0186             cmd = ["pacman", "--machinereadable", "-Fx", fileNamerx]
0187             output = subprocess.check_output(cmd)
0188             lines = output.split(b'\n')
0189             packages = [line.split(b'\0')[1].decode("utf-8") for line in lines if len(line)>0]
0190         #Debian
0191         elif Global.backend == "debian":
0192             prefix = "usr/bin/" if isExecutable else "/"
0193             packages = []
0194             for repo in Contents.pools():
0195                 packages = Contents.Archive(repo).findAllPackages(prefix + fileName)
0196                 if packages:
0197                     break
0198 
0199         return (fileName, requirement, packages)
0200 
0201     def locate(arg):
0202         (fileName, requirement, isExecutable) = arg
0203         ret = None
0204         if '*' in fileName:
0205             ret = Global.searchGlobFiles(fileName, requirement, isExecutable)
0206         else:
0207             ret = Global.searchFile(fileName, requirement, isExecutable)
0208         return ret
0209 
0210     def process(self, values):
0211         with concurrent.futures.ProcessPoolExecutor() as executor:
0212             #for fileName, req, packages in map(Global.locate, values):
0213             for fileName, req, packages in executor.map(Global.locate, values):
0214                 self.addResults(fileName, req, packages)
0215 
0216 def main():
0217     parser = argparse.ArgumentParser()
0218     parser.add_argument("command", help="[install|packages|packages-json|list]")
0219     parser.add_argument("backend", choices=["debian", "archlinux"])
0220     parser.add_argument("--verbose", action='store_true', help="increase output verbosity")
0221     args = parser.parse_args()
0222 
0223     Global.backend = args.backend
0224 
0225     g = Global()
0226 
0227     if args.verbose:
0228         g.printVerbose()
0229 
0230     if args.command == "install":
0231         g.installPackages()
0232     elif args.command == "packages":
0233         g.printPackages()
0234     elif args.command == "packages-json":
0235         g.printPackagesJson()
0236     else:
0237         correctCommand = args.command=="list"
0238         if not correctCommand:
0239             print("Wrong command '%s'" % args.command)
0240             print()
0241 
0242         print(" install:       triggers an install of the needed packages.")
0243         print(" packages:      lists the suggested packages, for distributors mostly.")
0244         print(" packages-json: lists the suggested packages, for distributors mostly.")
0245         print(" list:          this list")
0246         return 0 if correctCommand else 1
0247 
0248     return 0
0249 
0250 if __name__ == "__main__":
0251     sys.exit(main())