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())