diff --git a/bin/CraftCommands.py b/bin/CraftCommands.py index 00368ef71..2c2acb10c 100644 --- a/bin/CraftCommands.py +++ b/bin/CraftCommands.py @@ -1,335 +1,345 @@ # -*- coding: utf-8 -*- # Copyright Hannah von Reth # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. import tempfile import CraftBase from Blueprints.CraftDependencyPackage import CraftDependencyPackage, DependencyType from Blueprints.CraftVersion import CraftVersion from Blueprints.CraftPackageObject import CraftPackageObject from Utils.CraftTitleUpdater import CraftTitleUpdater from Utils import CraftTimer from options import * import glob import utils def doExec(package, action): with CraftTimer.Timer("%s for %s" % (action, package), 1): CraftCore.debug.step("Action: %s for %s" % (action, package)) ret = package.instance.execute(action) if not ret: if action == "fetch-binary": CraftCore.debug.step(f"{package} not found in cache") return False CraftCore.log.warning(f"Action: {action} for {package}:{package.version} FAILED") return ret def handlePackage(package, buildAction, directTargets): with CraftTimer.Timer(f"HandlePackage {package}", 3) as timer: success = True actions = [] timer.hook = lambda : utils.notify(f"Craft {buildAction} {'succeeded' if success else 'failed'}", f"{package} after {timer}", buildAction) CraftCore.debug.debug_line() CraftCore.debug.step(f"Handling package: {package}, action: {buildAction}") if buildAction == "all": if CraftCore.settings.getboolean("Packager", "UseCache", "False"): if doExec(package, "fetch-binary"): return True actions = ["fetch", "unpack", "compile", "cleanimage", "install", "post-install"] if CraftCore.settings.getboolean("ContinuousIntegration", "ClearBuildFolder", False): actions += ["cleanbuild"] actions += ["qmerge", "post-qmerge"] if CraftCore.settings.getboolean("Packager", "CreateCache"): onlyDirect = CraftCore.settings.getboolean("Packager", "CacheDirectTargetsOnly") if not onlyDirect or (onlyDirect and package in directTargets): actions += ["package"] else: actions = [buildAction] for action in actions: success = doExec(package, action) if not success: return False return True def resolvePackage(packageNames : [str], version : str=None) -> [CraftPackageObject]: package = CraftPackageObject(None) def resolveChildren(child): if child.isCategory(): for c in child.children.values(): resolveChildren(c) else: if version: UserOptions.addPackageOption(child, "version", version) package.children[child.name] = child for packageName in packageNames: child = CraftPackageObject.get(packageName) if not child: raise BlueprintNotFoundException(packageName) resolveChildren(child) return package def setOption(packageNames : [str], option : str) -> bool: if "=" not in option: CraftCore.log.error(f"Invalid option {option}") return False key, value = option.split("=", 1) for name in packageNames: package = CraftPackageObject.get(name) if not package: raise BlueprintNotFoundException(name) # create instance to make sure options are registered if not package.isCategory(): package.instance if not package: raise BlueprintNotFoundException(name) options = UserOptions.get(package) if not options.setOption(key, value): return False CraftCore.log.info(f"[{package}]\n{key}={getattr(options, key)}") return True def addBlueprintsRepository(url : str, args) -> bool: templateDir = os.path.join(CraftCore.standardDirs.craftBin(), "..", "internal_blueprints" ) with tempfile.TemporaryDirectory() as tmp: iniPath = os.path.join(tmp, "version.ini") parser = configparser.ConfigParser() parser.read(iniPath) parser.add_section("General") parser["General"]["branches"] = "master" parser["General"]["defaulttarget"] = "master" parser["General"]["gitUrl"] = url with open(iniPath, "wt+") as out: parser.write(out) CraftCore.settings.set("Blueprints", "Locations", templateDir) CraftCore.settings.set("InternalTemp", "add-bluprints-template.ini", iniPath) package = resolvePackage(["add-bluprints-template"]) return run(package, "fetch", args) def destroyCraftRoot() -> bool: settingsFiles = {"kdesettings.ini", "CraftSettings.ini", "BlueprintSettings.ini"} dirsToKeep = [CraftCore.standardDirs.downloadDir(), os.path.join(CraftCore.standardDirs.craftBin(), ".."), os.path.join(CraftCore.standardDirs.craftRoot(), "python"), CraftCore.standardDirs.blueprintRoot()] # dirs with possible interesting sub dirs maybeKeepDir = [ CraftCore.standardDirs.craftRoot(), CraftCore.standardDirs.etcDir(), os.path.join(CraftCore.standardDirs.etcDir(), "blueprints")# might contain blueprintRoot ] def deleteEntry(path): if utils.OsUtils.isLink(path): CraftCore.log.debug(f"Skipping symlink {path}") return if os.path.isdir(path): if any(os.path.exists(x) and os.path.samefile(path, x) for x in maybeKeepDir): CraftCore.log.debug(f"Path {path} in maybeKeepDir") for entry in os.listdir(path): deleteEntry(os.path.join(path, entry)) elif any(os.path.exists(x) and os.path.samefile(path, x) for x in dirsToKeep): CraftCore.log.debug(f"Path {path} in dirsToKeep") else: utils.cleanDirectory(path) utils.OsUtils.rmDir(path, True) else: if os.path.basename(path) not in settingsFiles: utils.OsUtils.rm(path, True) del CraftCore.installdb deleteEntry(CraftCore.standardDirs.craftRoot()) return True def readListFile(listFile): packageNames = [] parser = configparser.ConfigParser(allow_no_value=True) parser.read(listFile) for sections in parser.keys(): for packageName in parser[sections]: version = parser.get(sections, packageName) if version: UserOptions.setOptions([f"{packageName}.version={version}"]) packageNames.append(packageName) return packageNames def packageIsOutdated(package): installed = CraftCore.installdb.getInstalledPackages(package) if not installed: return True for pack in installed: version = pack.getVersion() if not version: continue cacheVersion = pack.getCacheVersion() if cacheVersion and cacheVersion != CraftBase.CraftBase.cacheVersion(): # can only happen for packages installed from cache return True return package.version != version def invoke(command : str, directTargets : [CraftPackageObject]) -> bool: args = {} key = command argsPattern = re.compile(r"(.+)\((.*)\)") argsMatch = argsPattern.findall(command) if argsMatch: key = argsMatch[0][0] args = eval(f"dict({','.join(argsMatch[0][1:])})") subs = key.split(".") for p in directTargets: instance = p.instance path = [] for sub in subs: path += [sub] if hasattr(instance, sub): attr = getattr(instance, sub) if callable(attr): instance = attr(**args) else: instance = attr else: CraftCore.debug.printOut(f"{p} has no member {'.'.join(path)}", file=sys.stderr) return False CraftCore.log.debug(f"--get {command} on {p} -> {type(instance)}:{instance}") CraftCore.debug.printOut(instance) return True def run(package : [CraftPackageObject], action : str, args) -> bool: if package.isIgnored(): CraftCore.log.info(f"Skipping package because it has been ignored: {package}") return True directTargets = package.children.values() CraftCore.state.directTargets = directTargets if action == "get": return invoke(args.get, directTargets) + if action == "install-to-desktop": + return installToDektop(directTargets) elif args.resolve_deps or action in ["all", "install-deps"]: # work on the dependencies depPackage = CraftDependencyPackage(package) if args.resolve_deps: if not args.resolve_deps.capitalize() in DependencyType.__members__: CraftCore.log.error(f"Invalid dependency type {args.resolve_deps}, valid types are {DependencyType.__members__}") return False depType = DependencyType.__getattr__(args.resolve_deps.capitalize()) print(depType) elif action == "install-deps": depType = DependencyType.Both else: depType = DependencyType.All depList = depPackage.getDependencies(depType=depType) packages = [] if not args.resolve_deps: for item in depList: if (args.ignoreInstalled and item in directTargets) or packageIsOutdated(item): packages.append(item) CraftCore.log.debug(f"dependency: {item}") elif item in directTargets: CraftCore.debug.step(f"{item} is up to date, nothing to do") else: packages = depList if not packages: CraftCore.log.debug("") if action == "install-deps": # we don't intend to build the package itself for x in directTargets: packages.remove(x) CraftTitleUpdater.usePackageProgressTitle(packages) while packages: info = packages[0] # in case we only want to see which packages are still to be build, simply return the package name if args.probe: CraftCore.log.warning(f"pretending {info}: {info.version}") else: if CraftCore.settings.getboolean("ContinuousIntegration", "Enabled", False): CraftCore.debug.debug_line() CraftCore.log.info(f"Status: {CraftTitleUpdater.instance}") if action in ["install-deps"]: action = "all" if not handlePackage(info, action, directTargets=directTargets): CraftCore.log.error(f"fatal error: package {info} {action} failed") return False packages.pop(0) else: for info in directTargets: if not handlePackage(info, action, directTargets=directTargets): return False CraftCore.debug.new_line() return True def cleanBuildFiles(cleanArchives, cleanImages, cleanInstalledImages, cleanBuildDir, packages): def cleanDir(dir): CraftCore.debug.printOut(f"Cleaning: {dir}") utils.cleanDirectory(dir) os.rmdir(dir) for p in packages: package = CraftPackageObject.get(p.path) if not package or package.isCategory(): continue CraftCore.log.debug(f"Checking package for unused files: {p.path}") instance = package.instance version = instance.version if version: imageGlob = instance.imageDir().replace(version, "*") builddirGlob = instance.buildDir().replace(version, "*") else: imageGlob = instance.imageDir() builddirGlob = instance.buildDir() # image directories if cleanImages: for dir in glob.glob(imageGlob): if package.isInstalled and not cleanInstalledImages: if dir == instance.imageDir(): continue cleanDir(dir) # archive directory if cleanArchives and os.path.exists(instance.archiveDir()): cleanDir(instance.archiveDir()) # build directory if cleanBuildDir: for dir in glob.glob(builddirGlob): cleanDir(dir) def updateInstalled(args) -> bool: package = CraftPackageObject(None) for packageName, _ in CraftCore.installdb.getDistinctInstalled(): p = CraftPackageObject.get(packageName) if p: package.children[p.name] = p return run(package, "all", args) + +def installToDektop(packages): + CraftCore.settings.set("Packager", "PackageType", "DesktopEntry") + for p in packages: + if not p.instance.createPackage(): + return False + return True + diff --git a/bin/Packager/DesktopEntry.py b/bin/Packager/DesktopEntry.py new file mode 100644 index 000000000..a97306e75 --- /dev/null +++ b/bin/Packager/DesktopEntry.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# Copyright Hannah von Reth +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + + +from Packager.PackagerBase import * + +from shells import Powershell + +class DesktopEntry(PackagerBase): + def createPackage(self): + for shortcut in self.defines["shortcuts"]: + shim = os.path.join(CraftCore.standardDirs.craftRoot(), "wrapper", shortcut["name"]) + if not utils.createShim(shim, + sys.executable, [os.path.join(CraftCore.standardDirs.craftBin(), "craft.py"), "--run", os.path.join(CraftCore.standardDirs.craftRoot(), shortcut["target"])]): + return False + if CraftCore.compiler.isWindows: + pwsh = Powershell() + shortcutPath = os.path.join(os.environ["APPDATA"], "Microsoft", "Windows", "Start Menu", "Programs", "Craft", + f"{shortcut['name']} {os.path.basename(CraftCore.standardDirs.craftRoot())}.lnk") + + pwsh.execute([os.path.join(CraftCore.standardDirs.craftBin(), "install-lnk.ps1"), + "-Path", pwsh.quote(shim), + "-WorkingDirectory", pwsh.quote(CraftCore.standardDirs.craftRoot()), + "-Name", pwsh.quote(shortcutPath), + "-Icon", pwsh.quote(os.path.join(CraftCore.standardDirs.craftRoot(), shortcut["target"])), + "-Description", pwsh.quote(shortcut.get("desciption", ""))]) + return True diff --git a/bin/Packager/TypePackager.py b/bin/Packager/TypePackager.py index b35ff88e6..3a6d514be 100644 --- a/bin/Packager/TypePackager.py +++ b/bin/Packager/TypePackager.py @@ -1,76 +1,77 @@ # -*- coding: utf-8 -*- # Copyright (c) 2015 Patrick Spendrin # Copyright Hannah von Reth # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. from Packager.CreateArchivePackager import * from Packager.MacDMGPackager import * from Packager.MSIFragmentPackager import * from Packager.NullsoftInstallerPackager import * from Packager.PortablePackager import * from Packager.SevenZipPackager import * from Packager.QtIFPackager import * from Packager.AppxPackager import * +from Packager.DesktopEntry import * class TypePackager(PackagerBase): """packager that is used in place of different other packagers The packager used can be decided at runtime """ def __init__(self): CraftCore.log.debug("TypePackager __init__") self.__packager = None self.changePackager(None) def changePackager(self, packager=None): if not packager: packager = CraftCore.settings.get("Packager", "PackageType", "") if not packager: if CraftCore.compiler.isWindows: packager = NullsoftInstallerPackager elif CraftCore.compiler.isMacOS: packager = MacDMGPackager else: packager = SevenZipPackager if isinstance(packager, str): if packager == "MultiCollectionPackager": packager = "NullsoftInstallerPackager" CraftCore.log.warning("MultiCollectionPackager is deprecated, please use NullsoftInstallerPackager") packager = eval(packager) if self.__packager: bases = list(self.__class__.__bases__) for i in range(len(bases)): if bases[i] == self.__packager: CraftCore.log.info(f"Replace Packager: {bases[i]} with {packager}") bases[i] = packager self.__class__.__bases__ = tuple(bases) else: self.__class__.__bases__ += (packager,) packager.__init__(self) self.__packager = packager def createPackage(self): return self.__packager.createPackage(self) diff --git a/bin/craft.py b/bin/craft.py index f39a79d51..967a24da6 100755 --- a/bin/craft.py +++ b/bin/craft.py @@ -1,264 +1,267 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright Holger Schroeder # Copyright Patrick Spendrin # Copyright Hannah von Reth # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. import argparse import collections import sys import CraftCommands import CraftSetupHelper import InstallDB import blueprintSearch from Blueprints.CraftPackageObject import * from CraftCore import CraftCore from Utils import CraftTimer from Utils.CraftTitleUpdater import CraftTitleUpdater from options import UserOptions class ActionHandler: class StoreTrueAction(argparse._StoreTrueAction): def __call__(self, parser, namespace, values, option_string=None): ActionHandler.StoreAction._addOrdered(namespace, self.dest, self.const) super().__call__(parser, namespace, values, option_string) class StoreAction(argparse._StoreAction): """http://stackoverflow.com/a/9028031""" def __call__(self, parser, namespace, values, option_string=None): ActionHandler.StoreAction._addOrdered(namespace, self.dest, values) super().__call__(parser, namespace, values, option_string) @staticmethod def _addOrdered(namespace, key, value): if not 'ordered_args' in namespace: setattr(namespace, 'ordered_args', collections.OrderedDict()) namespace.ordered_args[key] = value def __init__(self, parser): self.parser = parser self.actions = {} - def _addAction(self, actionName, help=None, **kwargs): + def _addAction(self, actionName, help="", **kwargs): + if help is not argparse.SUPPRESS: + help = f"[Action] {help}" arg = self.parser.add_argument("--%s" % actionName, - help="[Action] %s" % (help if help else ""), **kwargs) + help=help, **kwargs) self.actions[arg.dest] = actionName def addAction(self, actionName, **kwargs): self._addAction(actionName, action=ActionHandler.StoreTrueAction, **kwargs) def addActionWithArg(self, actionName, **kwargs): self._addAction(actionName, action=ActionHandler.StoreAction, **kwargs) def parseFinalAction(self, args, defaultAction): '''Returns the list of actions or [defaultAction]''' return [self.actions[x] for x in args.ordered_args.keys()] if hasattr(args, "ordered_args") else [defaultAction] def main(): parser = argparse.ArgumentParser(prog="Craft", description="Craft is an open source meta build system and package manager." "It manages dependencies and builds libraries and applications from source, on Windows, Mac, Linux and FreeBSD.", epilog="For more information visit https://community.kde.org/Craft.\n" "Send feedback to .") parser.add_argument("-p", "--probe", action="store_true", help="probing: craft will only look which files it has to build according to the list of installed files and according to the dependencies of the package.") parser.add_argument("--list-file", action="store", help="Build all packages from the ini file provided") parser.add_argument("--options", action="append", default=CraftCore.settings.getList("General", "Options", ""), help="Set craft property from string . An example for is extragear/kdevelop.version=5.3 or [Compile]MakeProgram=jom.") parser.add_argument("-q", "--stayquiet", action="store_true", dest="stayQuiet", help="quiet: there should be no output - The verbose level should be 0") parser.add_argument("--create-cache", action="store_true", dest="createCache", default=CraftCore.settings.getboolean("Packager", "CreateCache", "False"), help="Create a binary cache, the setting is overwritten by --no-cache") parser.add_argument("--use-cache", action="store_true", dest="useCache", default=CraftCore.settings.getboolean("Packager", "UseCache", "False"), help="Use a binary cache, the setting is overwritten by --no-cache") parser.add_argument("--no-cache", action="store_true", dest="noCache", default=False, help="Don't create or use the binary cache") parser.add_argument("--destroy-craft-root", action="store_true", dest="doDestroyCraftRoot", default=False, help="DANGEROUS: Recursively delete everything in the Craft root directory besides the CraftSettings.ini, the download directory and the craft folder itself") parser.add_argument("--offline", action="store_true", default=CraftCore.settings.getboolean("General", "WorkOffline", False), help="do not try to connect to the internet: KDE packages will try to use an existing source tree and other packages would try to use existing packages in the download directory.\ If that doesn't work, the build will fail.") parser.add_argument("--buildtype", choices=["Release", "RelWithDebInfo", "MinSizeRel", "Debug"], dest="buildType", default=CraftCore.settings.get("Compile", "BuildType", "RelWithDebInfo"), help="This will override the build type set in your CraftSettings.ini.") parser.add_argument("-v", "--verbose", action="count", default=int(CraftCore.settings.get("CraftDebug", "Verbose", "0")), help=" verbose: increases the verbose level of craft. Default is 1. verbose level 1 contains some notes from craft, all output of cmake, make and other programs that are used.\ verbose level 2a dds an option VERBOSE=1 to make and craft is more verbose highest level is verbose level 3.") parser.add_argument("-i", "--ignoreInstalled", action="store_true", help="ignore install: using this option will install a package over an existing install. This can be useful if you want to check some new code and your last build isn't that old.") parser.add_argument("--resolve-deps", action="store", help="Similar to -i, all dependencies will be resolved and the action is applied on them") parser.add_argument("--target", action="store", help="This will override the build of the default target.") parser.add_argument("--search", action="store_true", help="This will search for a package or a description matching or similar to the search term.") parser.add_argument("--src-dir", action="store", dest="srcDir", help="This will override the source dir and enable the offline mode") parser.add_argument("--ci-mode", action="store_true", default=CraftCore.settings.getboolean("ContinuousIntegration", "Enabled", False), dest="ciMode", help="Enables the ci mode") parser.add_argument("--add-blueprint-repository", action="store", help="Installs a blueprint repository", metavar="URL") actionHandler = ActionHandler(parser) for x in sorted(["fetch", "fetch-binary", "unpack", "configure", ("compile",{"help":"Same as --configure --make"}), "make", - "install", "install-deps", "qmerge", "post-qmerge", "post-install", "package", "unmerge", "test", "createpatch"], key=lambda x: x[0] if isinstance(x, tuple) else x): + "install", "install-deps", "qmerge", "post-qmerge", "post-install", "package", "unmerge", "test", "createpatch", + ("install-to-desktop", {"help":argparse.SUPPRESS})], key=lambda x: x[0] if isinstance(x, tuple) else x): if isinstance(x, tuple): actionHandler.addAction(x[0], **x[1]) else: actionHandler.addAction(x) actionHandler.addAction("update", help="Update all installed packages") # read-only actions actionHandler.addAction("print-installed", help="This will show a list of all packages that are installed currently.") actionHandler.addAction("print-files", help="Print the files installed by the package and exit") actionHandler.addActionWithArg("search-file", help="Print packages owning the file") actionHandler.addActionWithArg("get", help="Get any value from a Blueprint") actionHandler.addActionWithArg("set", help="Permanently set a config value of a Blueprint") actionHandler.addActionWithArg("run", nargs="+", help="Run an application in the Craft environment") actionHandler.addAction("clean-unused", help="Clean unused files of all packages") # other actions parser.add_argument("--version", action="version", version = f"%(prog)s {CraftSetupHelper.SetupHelper.CraftVersion}") parser.add_argument("packageNames", nargs=argparse.REMAINDER) args = parser.parse_args() if args.stayQuiet: CraftCore.debug.setVerbose(-1) elif args.verbose: CraftCore.debug.setVerbose(args.verbose) CraftCore.settings.set("General", "WorkOffline", args.offline or args.srcDir is not None) CraftCore.settings.set("Compile", "BuildType", args.buildType) CraftCore.settings.set("General", "Options", ";".join(args.options)) CraftCore.settings.set("Packager", "CreateCache", not args.noCache and args.createCache) CraftCore.settings.set("Packager", "UseCache", not args.noCache and args.useCache) CraftCore.settings.set("ContinuousIntegration", "SourceDir", args.srcDir) CraftCore.settings.set("ContinuousIntegration", "Enabled", args.ciMode) CraftSetupHelper.SetupHelper.printBanner() if args.doDestroyCraftRoot: return CraftCommands.destroyCraftRoot() if args.run: return utils.system(args.run, shell=True) if args.add_blueprint_repository: return CraftCommands.addBlueprintsRepository(args.add_blueprint_repository, args) if CraftCore.settings.getboolean("Packager", "CreateCache"): # we are in cache creation mode, ensure to create a 7z image and not an installer CraftCore.settings.set("Packager", "PackageType", "SevenZipPackager") UserOptions.setOptions(args.options) if args.search: for package in args.packageNames: blueprintSearch.printSearch(package) return True for action in actionHandler.parseFinalAction(args, "all"): tempArgs = copy.deepcopy(args) if action in ["install-deps", "package"]: tempArgs.ignoreInstalled = True CraftCore.log.debug("buildAction: %s" % action) CraftCore.log.debug("doPretend: %s" % tempArgs.probe) CraftCore.log.debug("packageName: %s" % tempArgs.packageNames) CraftCore.log.debug("buildType: %s" % tempArgs.buildType) CraftCore.log.debug("verbose: %d" % CraftCore.debug.verbose()) CraftCore.log.debug("Craft: %s" % CraftCore.standardDirs.craftRoot()) packageNames = tempArgs.packageNames if tempArgs.list_file: if not os.path.exists(tempArgs.list_file): CraftCore.log.error(f"List file {tempArgs.list_file!r} does not exist") return False if not packageNames: packageNames = [] packageNames += CraftCommands.readListFile(tempArgs.list_file) if action == "print-installed": InstallDB.printInstalled() elif action == "search-file": InstallDB.printPackagesForFileSearch(tempArgs.search_file) elif action == "set": CraftCommands.setOption(packageNames, args.set) elif action == "clean-unused": CraftCommands.cleanBuildFiles(cleanArchives=True, cleanImages=True, cleanInstalledImages=False, cleanBuildDir=True, packages=blueprintSearch.packages()) elif action == "update": return CraftCommands.updateInstalled(tempArgs) else: if not packageNames: return True package = CraftCommands.resolvePackage(packageNames, version=tempArgs.target) if not CraftCommands.run(package, action, tempArgs): return False return True if __name__ == '__main__': success = False with CraftTimer.Timer("Craft", 0) as timer: CraftTitleUpdater.instance = CraftTitleUpdater() if not "CRAFT_NOTITLEUPDATE" in os.environ and not "--ci-mode" in sys.argv: CraftTitleUpdater.instance.start(f"({CraftCore.standardDirs.craftRoot()}) craft " + " ".join(sys.argv[1:]), timer) try: success = main() except KeyboardInterrupt: pass except BlueprintNotFoundException as e: CraftCore.log.error(e) blueprintSearch.printSearch(e.packageName) except BlueprintException as e: if 0 <= CraftCore.debug.verbose() < 2: CraftCore.log.error(e) CraftCore.log.debug(e, exc_info=e.exception or e) else: CraftCore.log.error(e, exc_info=e.exception or e) except Exception as e: CraftCore.log.error(e, exc_info=e) finally: CraftTitleUpdater.instance.stop() if not success: exit(1) diff --git a/bin/install-lnk.ps1 b/bin/install-lnk.ps1 new file mode 100644 index 000000000..f5691371e --- /dev/null +++ b/bin/install-lnk.ps1 @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Copyright Hannah von Reth +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +param( + [alias("Path")][string]$Script:path, + [alias("Arguments")][string]$Script:arguments, + [alias("WorkingDirectory")][string]$Script:workingDirectory, + [alias("Name")][string]$Script:name, + [alias("Icon")][string]$Script:icon, + [alias("Description")][string]$Script:description + ) + +Write-Host "Installing shortcut to: '$Script:name'" + +$Shell = New-Object -ComObject ("WScript.Shell") +$ShortCut = $Shell.CreateShortcut($Script:name) +$ShortCut.TargetPath="$Script:path" +$ShortCut.Arguments="$Script:arguments" +$ShortCut.WorkingDirectory = "$Script:workingDirectory"; +$ShortCut.IconLocation = "$Script:icon"; +$ShortCut.Description = "$Script:description"; +$ShortCut.Save()