Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP7:GA
xen.21119
pygrub-python3-conversion.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File pygrub-python3-conversion.patch of Package xen.21119
Index: xen-4.10.0-testing/tools/pygrub/src/pygrub =================================================================== --- xen-4.10.0-testing.orig/tools/pygrub/src/pygrub +++ xen-4.10.0-testing/tools/pygrub/src/pygrub @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#!/usr/bin/python3 # # pygrub - simple python-based bootloader for Xen # @@ -18,7 +18,8 @@ import logging import platform import xen.lowlevel.xc -import curses, _curses, curses.wrapper, curses.textpad, curses.ascii +import curses, _curses, curses.textpad, curses.ascii +from curses import wrapper import getopt import fsimage @@ -51,7 +52,7 @@ def enable_cursor(ison): except _curses.error: pass -DISK_TYPE_RAW, DISK_TYPE_HYBRIDISO, DISK_TYPE_DOS = range(3) +DISK_TYPE_RAW, DISK_TYPE_HYBRIDISO, DISK_TYPE_DOS = list(range(3)) def identify_disk_image(file): """Detect DOS partition table or HybridISO format.""" fd = os.open(file, os.O_RDONLY) @@ -78,7 +79,7 @@ def get_solaris_slice(file, offset): buf = os.read(fd, 512) os.close(fd) if struct.unpack("<H", buf[508:510])[0] != DKL_MAGIC: - raise RuntimeError, "Invalid disklabel magic" + raise RuntimeError("Invalid disklabel magic") nslices = struct.unpack("<H", buf[30:32])[0] @@ -89,7 +90,7 @@ def get_solaris_slice(file, offset): if slicetag == V_ROOT: return slicesect * SECTOR_SIZE - raise RuntimeError, "No root slice found" + raise RuntimeError("No root slice found") def get_fs_offset_gpt(file): fd = os.open(file, os.O_RDONLY) @@ -424,20 +425,17 @@ class Grub: we're being given a raw config file rather than a disk image.""" if not os.access(fn, os.R_OK): - raise RuntimeError, "Unable to access %s" %(fn,) + raise RuntimeError("Unable to access %s" %(fn,)) - cfg_list = map(lambda x: (x,grub.GrubConf.Grub2ConfigFile), - ["/boot/grub/grub.cfg", "/grub/grub.cfg", - "/boot/grub2/grub.cfg", "/grub2/grub.cfg"]) + \ - map(lambda x: (x,grub.ExtLinuxConf.ExtLinuxConfigFile), - ["/boot/isolinux/isolinux.cfg", + cfg_list = [(x,grub.GrubConf.Grub2ConfigFile) for x in ["/boot/grub/grub.cfg", "/grub/grub.cfg", + "/boot/grub2/grub.cfg", "/grub2/grub.cfg"]] + \ + [(x,grub.ExtLinuxConf.ExtLinuxConfigFile) for x in ["/boot/isolinux/isolinux.cfg", "/boot/extlinux/extlinux.conf", "/boot/extlinux.conf", "/extlinux/extlinux.conf", - "/extlinux.conf"]) + \ - map(lambda x: (x,grub.GrubConf.GrubConfigFile), - ["/boot/grub/menu.lst", "/boot/grub/grub.conf", - "/grub/menu.lst", "/grub/grub.conf"]) + "/extlinux.conf"]] + \ + [(x,grub.GrubConf.GrubConfigFile) for x in ["/boot/grub/menu.lst", "/boot/grub/grub.conf", + "/grub/menu.lst", "/grub/grub.conf"]] if not fs: # set the config file and parse it @@ -449,7 +447,7 @@ class Grub: for f,parser in cfg_list: if fs.file_exists(f): - print >>sys.stderr, "Using %s to parse %s" % (parser,f) + print("Using %s to parse %s" % (parser,f), file=sys.stderr) self.cf = parser() self.cf.filename = f break @@ -459,7 +457,7 @@ class Grub: # limit read size to avoid pathological cases buf = f.read(FS_READ_MAX) del f - self.cf.parse(buf) + self.cf.parse(buf.decode()) def image_index(self): if isinstance(self.cf.default, int): @@ -603,7 +601,7 @@ class Grub: def get_entry_idx(cf, entry): # first, see if the given entry is numeric try: - idx = string.atoi(entry) + idx = int(entry) return idx except ValueError: pass @@ -636,21 +634,21 @@ def run_grub(file, entry, fs, cfg_args): chosencfg["args"] = cfg_args return chosencfg if g.__dict__.get('cf', None) is None: - raise RuntimeError, "couldn't find bootloader config file in the image provided." + raise RuntimeError("couldn't find bootloader config file in the image provided.") else: return if list_entries: for i in range(len(g.cf.images)): img = g.cf.images[i] - print "title: %s" % img.title - print " root: %s" % img.root - print " kernel: %s" % img.kernel[1] - print " args: %s" % img.args - print " initrd: %s" % img.initrd[1] + print("title: %s" % img.title) + print(" root: %s" % img.root) + print(" kernel: %s" % img.kernel[1]) + print(" args: %s" % img.args) + print(" initrd: %s" % img.initrd[1]) if interactive and not list_entries: - curses.wrapper(run_main) + wrapper(run_main) else: sel = g.image_index() @@ -661,7 +659,7 @@ def run_grub(file, entry, fs, cfg_args): sel = idx if sel == -1: - print "No kernel image selected!" + print("No kernel image selected!") sys.exit(1) try: @@ -759,7 +757,7 @@ def format_sxp(kernel, ramdisk, args): def format_simple(kernel, ramdisk, args, sep): for check in (kernel, ramdisk, args): if check is not None and sep in check: - raise RuntimeError, "simple format cannot represent delimiter-containing value" + raise RuntimeError("simple format cannot represent delimiter-containing value") s = ("kernel %s" % kernel) + sep if ramdisk: s += ("ramdisk %s" % ramdisk) + sep @@ -772,7 +770,7 @@ if __name__ == "__main__": sel = None def usage(): - print >> sys.stderr, "Usage: %s [-q|--quiet] [-i|--interactive] [-l|--list-entries] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0] [--offset=] <image>" %(sys.argv[0],) + print("Usage: %s [-q|--quiet] [-i|--interactive] [-l|--list-entries] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0] [--offset=] <image>" %(sys.argv[0],), file=sys.stderr) def copy_from_image(fs, file_to_read, file_type, output_directory, not_really): @@ -783,8 +781,8 @@ if __name__ == "__main__": sys.exit("The requested %s file does not exist" % file_type) try: datafile = fs.open_file(file_to_read) - except Exception, e: - print >>sys.stderr, e + except Exception as e: + print(e, file=sys.stderr) sys.exit("Error opening %s in guest" % file_to_read) (tfd, ret) = tempfile.mkstemp(prefix="boot_"+file_type+".", dir=output_directory) @@ -799,8 +797,8 @@ if __name__ == "__main__": return ret try: os.write(tfd, data) - except Exception, e: - print >>sys.stderr, e + except Exception as e: + print(e, file=sys.stderr) os.close(tfd) os.unlink(ret) del datafile @@ -864,7 +862,7 @@ if __name__ == "__main__": try: part_offs = [ int(a) ] except ValueError: - print "offset value must be an integer" + print("offset value must be an integer") usage() sys.exit(1) elif o in ("--entry",): @@ -877,23 +875,23 @@ if __name__ == "__main__": debug = True elif o in ("--output-format",): if a not in ["sxp", "simple", "simple0"]: - print "unknown output format %s" % a + print("unknown output format %s" % a) usage() sys.exit(1) output_format = a elif o in ("--output-directory",): if not os.path.isdir(a): - print "%s is not an existing directory" % a + print("%s is not an existing directory" % a) sys.exit(1) output_directory = a if debug: - logging.basicConfig(level=logging.DEBUG) + logging.basicConfig(level=logging.DEBUG) try: - os.makedirs(output_directory, 0700) - except OSError,e: + os.makedirs(output_directory, 0o700) + except OSError as e: if (e.errno == errno.EEXIST) and os.path.isdir(output_directory): pass else: @@ -907,10 +905,10 @@ if __name__ == "__main__": # debug if isconfig: chosencfg = run_grub(file, entry, fs, incfg["args"]) - print " kernel: %s" % chosencfg["kernel"] + print(" kernel: %s" % chosencfg["kernel"]) if chosencfg["ramdisk"]: - print " initrd: %s" % chosencfg["ramdisk"] - print " args: %s" % chosencfg["args"] + print(" initrd: %s" % chosencfg["ramdisk"]) + print(" args: %s" % chosencfg["args"]) sys.exit(0) # if boot filesystem is set then pass to fsimage.open @@ -947,7 +945,7 @@ if __name__ == "__main__": # IOErrors raised by fsimage.open # RuntimeErrors raised by run_grub if no menu.lst present if debug: - traceback.print_exc() + traceback.print_exc() fs = None continue @@ -956,7 +954,7 @@ if __name__ == "__main__": # Did looping through partitions find us a kernel? if fs is None: - raise RuntimeError, "Unable to find partition containing kernel" + raise RuntimeError("Unable to find partition containing kernel") bootcfg["kernel"] = copy_from_image(fs, chosencfg["kernel"], "kernel", output_directory, not_really) @@ -991,5 +989,5 @@ if __name__ == "__main__": ostring = format_simple(bootcfg["kernel"], bootcfg["ramdisk"], args, "\0") sys.stdout.flush() - os.write(fd, ostring) + os.write(fd, ostring.encode('utf-8')) Index: xen-4.10.0-testing/tools/pygrub/src/GrubConf.py =================================================================== --- xen-4.10.0-testing.orig/tools/pygrub/src/GrubConf.py +++ xen-4.10.0-testing/tools/pygrub/src/GrubConf.py @@ -44,7 +44,7 @@ def get_path(s): return (None, s) idx = s.find(')') if idx == -1: - raise ValueError, "Unable to find matching ')'" + raise ValueError("Unable to find matching ')'") d = s[:idx] return (GrubDiskPart(d), s[idx + 1:]) @@ -100,7 +100,7 @@ class _GrubImage(object): " initrd: %s\n" %(self.title, self.root, self.kernel, self.args, self.initrd)) def _parse(self, lines): - map(self.set_from_line, lines) + list(map(self.set_from_line, lines)) def reset(self, lines): self._root = self._initrd = self._kernel = self._args = None @@ -141,7 +141,7 @@ class GrubImage(_GrubImage): def set_from_line(self, line, replace = None): (com, arg) = grub_exact_split(line, 2) - if self.commands.has_key(com): + if com in self.commands: if self.commands[com] is not None: setattr(self, self.commands[com], arg.strip()) else: @@ -177,7 +177,7 @@ class _GrubConfigFile(object): self.parse() def parse(self, buf = None): - raise RuntimeError, "unimplemented parse function" + raise RuntimeError("unimplemented parse function") def hasPasswordAccess(self): return self.passwordAccess @@ -201,7 +201,7 @@ class _GrubConfigFile(object): import crypt if crypt.crypt(password, pwd[1]) == pwd[1]: return True - except Exception, e: + except Exception as e: self.passExc = "Can't verify password: %s" % str(e) return False @@ -213,7 +213,7 @@ class _GrubConfigFile(object): def set(self, line): (com, arg) = grub_exact_split(line, 2) - if self.commands.has_key(com): + if com in self.commands: if self.commands[com] is not None: setattr(self, self.commands[com], arg.strip()) else: @@ -232,8 +232,8 @@ class _GrubConfigFile(object): else: self._default = val - if self._default < 0: - raise ValueError, "default must be positive number" + if int(self._default) < 0: + raise ValueError("default must be positive number") default = property(_get_default, _set_default) def set_splash(self, val): @@ -265,7 +265,7 @@ class GrubConfigFile(_GrubConfigFile): def parse(self, buf = None): if buf is None: if self.filename is None: - raise ValueError, "No config file defined to parse!" + raise ValueError("No config file defined to parse!") f = open(self.filename, 'r') lines = f.readlines() @@ -296,7 +296,7 @@ class GrubConfigFile(_GrubConfigFile): continue (com, arg) = grub_exact_split(l, 2) - if self.commands.has_key(com): + if com in self.commands: if self.commands[com] is not None: setattr(self, self.commands[com], arg.strip()) else: @@ -328,7 +328,7 @@ class Grub2Image(_GrubImage): if com == "set": (com,arg) = grub2_handle_set(arg) - if self.commands.has_key(com): + if com in self.commands: if self.commands[com] is not None: setattr(self, self.commands[com], arg.strip()) else: @@ -364,7 +364,7 @@ class Grub2ConfigFile(_GrubConfigFile): def parse(self, buf = None): if buf is None: if self.filename is None: - raise ValueError, "No config file defined to parse!" + raise ValueError("No config file defined to parse!") f = open(self.filename, 'r') lines = f.readlines() @@ -398,7 +398,7 @@ class Grub2ConfigFile(_GrubConfigFile): title_match = re.match('^menuentry ["\'](.*?)["\'] (.*){', l) if title_match: if img is not None: - raise RuntimeError, "syntax error: cannot nest menuentry (%d %s)" % (len(img),img) + raise RuntimeError("syntax error: cannot nest menuentry (%d %s)" % (len(img),img)) img = [] title = title_match.group(1) if not l.endswith('}'): @@ -416,7 +416,7 @@ class Grub2ConfigFile(_GrubConfigFile): menu_level -= 1 continue else: - raise RuntimeError, "syntax error: closing brace without menuentry" + raise RuntimeError("syntax error: closing brace without menuentry") self.add_image(Grub2Image(title, img)) img = None @@ -431,7 +431,7 @@ class Grub2ConfigFile(_GrubConfigFile): if com == "set": (com,arg) = grub2_handle_set(arg) - if self.commands.has_key(com): + if com in self.commands: if self.commands[com] is not None: arg_strip = arg.strip() if arg_strip == "${saved_entry}" or arg_strip == "${next_entry}": @@ -446,7 +446,7 @@ class Grub2ConfigFile(_GrubConfigFile): logging.debug("Unknown directive %s" %(com,)) if img is not None: - raise RuntimeError, "syntax error: end of file with open menuentry(%d %s)" % (len(img),img) + raise RuntimeError("syntax error: end of file with open menuentry(%d %s)" % (len(img),img)) if self.hasPassword(): self.setPasswordAccess(False) @@ -465,12 +465,12 @@ class Grub2ConfigFile(_GrubConfigFile): if __name__ == "__main__": if len(sys.argv) < 3: - raise RuntimeError, "Need a grub version (\"grub\" or \"grub2\") and a grub.conf or grub.cfg to read" + raise RuntimeError("Need a grub version (\"grub\" or \"grub2\") and a grub.conf or grub.cfg to read") if sys.argv[1] == "grub": g = GrubConfigFile(sys.argv[2]) elif sys.argv[1] == "grub2": g = Grub2ConfigFile(sys.argv[2]) else: - raise RuntimeError, "Unknown config type %s" % sys.argv[1] + raise RuntimeError("Unknown config type %s" % sys.argv[1]) for i in g.images: - print i #, i.title, i.root, i.kernel, i.args, i.initrd + print(i) #, i.title, i.root, i.kernel, i.args, i.initrd Index: xen-4.10.0-testing/tools/pygrub/src/ExtLinuxConf.py =================================================================== --- xen-4.10.0-testing.orig/tools/pygrub/src/ExtLinuxConf.py +++ xen-4.10.0-testing/tools/pygrub/src/ExtLinuxConf.py @@ -12,7 +12,7 @@ import sys, re, os import logging -import GrubConf +from . import GrubConf class ExtLinuxImage(object): def __init__(self, lines, path): @@ -32,7 +32,7 @@ class ExtLinuxImage(object): self.lines = [] self.path = path self.root = "" - map(self.set_from_line, lines) + list(map(self.set_from_line, lines)) def set_from_line(self, line, replace = None): (com, arg) = GrubConf.grub_exact_split(line, 2) @@ -67,7 +67,7 @@ class ExtLinuxImage(object): setattr(self, "initrd", a.replace("initrd=", "")) arg = arg.replace(a, "") - if com is not None and self.commands.has_key(com): + if com is not None and com in self.commands: if self.commands[com] is not None: setattr(self, self.commands[com], re.sub('^"(.+)"$', r"\1", arg.strip())) else: @@ -136,7 +136,7 @@ class ExtLinuxConfigFile(object): def parse(self, buf = None): if buf is None: if self.filename is None: - raise ValueError, "No config file defined to parse!" + raise ValueError("No config file defined to parse!") f = open(self.filename, 'r') lines = f.readlines() @@ -167,7 +167,7 @@ class ExtLinuxConfigFile(object): (com, arg) = GrubConf.grub_exact_split(l, 2) com = com.lower() - if self.commands.has_key(com): + if com in self.commands: if self.commands[com] is not None: setattr(self, self.commands[com], arg.strip()) else: @@ -207,8 +207,8 @@ class ExtLinuxConfigFile(object): if __name__ == "__main__": if len(sys.argv) < 2: - raise RuntimeError, "Need a configuration file to read" + raise RuntimeError("Need a configuration file to read") g = ExtLinuxConfigFile(sys.argv[1]) for i in g.images: - print i - print g.default + print(i) + print(g.default) Index: xen-4.10.0-testing/tools/pygrub/src/LiloConf.py =================================================================== --- xen-4.10.0-testing.orig/tools/pygrub/src/LiloConf.py +++ xen-4.10.0-testing/tools/pygrub/src/LiloConf.py @@ -4,7 +4,7 @@ import sys, re, os import logging -import GrubConf +from . import GrubConf class LiloImage(object): def __init__(self, lines, path): @@ -24,12 +24,12 @@ class LiloImage(object): self.lines = [] self.path = path self.root = "" - map(self.set_from_line, lines) + list(map(self.set_from_line, lines)) def set_from_line(self, line, replace = None): (com, arg) = GrubConf.grub_exact_split(line, 2) - if self.commands.has_key(com): + if com in self.commands: if self.commands[com] is not None: setattr(self, self.commands[com], re.sub('^"(.+)"$', r"\1", arg.strip())) else: @@ -97,7 +97,7 @@ class LiloConfigFile(object): def parse(self, buf = None): if buf is None: if self.filename is None: - raise ValueError, "No config file defined to parse!" + raise ValueError("No config file defined to parse!") f = open(self.filename, 'r') lines = f.readlines() @@ -127,7 +127,7 @@ class LiloConfigFile(object): continue (com, arg) = GrubConf.grub_exact_split(l, 2) - if self.commands.has_key(com): + if com in self.commands: if self.commands[com] is not None: setattr(self, self.commands[com], arg.strip()) else: @@ -170,8 +170,8 @@ class LiloConfigFile(object): if __name__ == "__main__": if len(sys.argv) < 2: - raise RuntimeError, "Need a lilo.conf to read" + raise RuntimeError("Need a lilo.conf to read") g = LiloConfigFile(sys.argv[1]) for i in g.images: - print i #, i.title, i.root, i.kernel, i.args, i.initrd - print g.default + print(i) #, i.title, i.root, i.kernel, i.args, i.initrd + print(g.default) Index: xen-4.10.0-testing/tools/pygrub/src/fsimage/fsimage.c =================================================================== --- xen-4.10.0-testing.orig/tools/pygrub/src/fsimage/fsimage.c +++ xen-4.10.0-testing/tools/pygrub/src/fsimage/fsimage.c @@ -66,12 +66,12 @@ fsimage_file_read(fsimage_file_t *file, bufsize = size ? size : 4096; - if ((buffer = PyString_FromStringAndSize(NULL, bufsize)) == NULL) + if ((buffer = PyBytes_FromStringAndSize(NULL, bufsize)) == NULL) return (NULL); while (1) { int err; - void *buf = PyString_AS_STRING(buffer) + bytesread; + void *buf = PyBytes_AS_STRING(buffer) + bytesread; err = fsi_pread_file(file->file, buf, bufsize, bytesread + offset); @@ -91,12 +91,12 @@ fsimage_file_read(fsimage_file_t *file, if (bufsize == 0) break; } else { - if (_PyString_Resize(&buffer, bytesread + bufsize) < 0) + if (_PyBytes_Resize(&buffer, bytesread + bufsize) < 0) return (NULL); } } - _PyString_Resize(&buffer, bytesread); + _PyBytes_Resize(&buffer, bytesread); return (buffer); } @@ -107,7 +107,7 @@ PyDoc_STRVAR(fsimage_file_read__doc__, "file. If offset is specified as well, read from the given " "offset.\n"); -static struct PyMethodDef fsimage_file_methods[] = { +static PyMethodDef fsimage_file_methods[] = { { "read", (PyCFunction) fsimage_file_read, METH_VARARGS|METH_KEYWORDS, fsimage_file_read__doc__ }, { NULL, NULL, 0, NULL } @@ -116,7 +116,13 @@ static struct PyMethodDef fsimage_file_m static PyObject * fsimage_file_getattr(fsimage_file_t *file, char *name) { - return (Py_FindMethod(fsimage_file_methods, (PyObject *)file, name)); + PyMethodDef *ml = fsimage_file_methods; + for (; ml->ml_name != NULL; ml++) { + if (name[0] == ml->ml_name[0] && + strcmp(name+1, ml->ml_name+1) == 0) + return PyCFunction_New(ml, (PyObject *)file); + } + return (NULL); } static void @@ -130,8 +136,7 @@ fsimage_file_dealloc(fsimage_file_t *fil static char fsimage_file_type__doc__[] = "Filesystem image file"; PyTypeObject fsimage_file_type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ + PyVarObject_HEAD_INIT(&PyType_Type, 0) "fsimage.file", /* tp_name */ sizeof(fsimage_file_t), /* tp_size */ 0, /* tp_itemsize */ @@ -207,7 +212,7 @@ PyDoc_STRVAR(fsimage_fs_file_exists__doc "file_exists(fs, name) - lookup name in the given fs and return " "True if it exists"); -static struct PyMethodDef fsimage_fs_methods[] = { +static PyMethodDef fsimage_fs_methods[] = { { "open_file", (PyCFunction) fsimage_fs_open_file, METH_VARARGS|METH_KEYWORDS, fsimage_fs_open_file__doc__ }, { "file_exists", (PyCFunction) fsimage_fs_file_exists, @@ -218,7 +223,13 @@ static struct PyMethodDef fsimage_fs_met static PyObject * fsimage_fs_getattr(fsimage_fs_t *fs, char *name) { - return (Py_FindMethod(fsimage_fs_methods, (PyObject *)fs, name)); + PyMethodDef *ml = fsimage_fs_methods; + for (; ml->ml_name != NULL; ml++) { + if (name[0] == ml->ml_name[0] && + strcmp(name+1, ml->ml_name+1) == 0) + return PyCFunction_New(ml, (PyObject *)fs); + } + return (NULL); } static void @@ -232,8 +243,7 @@ fsimage_fs_dealloc (fsimage_fs_t *fs) PyDoc_STRVAR(fsimage_fs_type__doc__, "Filesystem image"); PyTypeObject fsimage_fs_type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /* ob_size */ + PyVarObject_HEAD_INIT(&PyType_Type, 0) "fsimage.fs", /* tp_name */ sizeof(fsimage_fs_t), /* tp_size */ 0, /* tp_itemsize */ @@ -308,7 +318,7 @@ PyDoc_STRVAR(fsimage_getbootstring__doc_ "getbootstring(fs) - Return the boot string needed for this file system " "or NULL if none is needed.\n"); -static struct PyMethodDef fsimage_module_methods[] = { +static PyMethodDef fsimage_module_methods[] = { { "open", (PyCFunction)fsimage_open, METH_VARARGS|METH_KEYWORDS, fsimage_open__doc__ }, { "getbootstring", (PyCFunction)fsimage_getbootstring, @@ -316,8 +326,17 @@ static struct PyMethodDef fsimage_module { NULL, NULL, 0, NULL } }; +static struct PyModuleDef fsimage_module = +{ + PyModuleDef_HEAD_INIT, + "fsimage", + "", + -1, + fsimage_module_methods +}; + PyMODINIT_FUNC -initfsimage(void) +PyInit_fsimage(void) { - Py_InitModule("fsimage", fsimage_module_methods); + return PyModule_Create(&fsimage_module); }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor