diff --git a/LICENSE.txt b/LICENSE.txt index 6a0d66c..be6ba56 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -86,7 +86,7 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the + otherwise, or (ii) ownership of fifty percent (50) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity @@ -242,330 +242,22 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. -END OF TERMS AND CONDITIONS - -sol2 License ------------------------ - -Copyright (c) 2013-2018 Rapptz, ThePhD, and contributors - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -Lua License ------------------------ - -Copyright (c) 1994-2018 Lua.org, PUC-Rio. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -cURL License ------------------------ - -This code uses a permissive license. Please use the following -attribution in the documentation of the open source code. - -Copyright (c) 1996 - 2018, Daniel Stenberg, daniel@haxx.se, and many -contributors, see the THANKS file. - -All rights reserved. - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF -THIRD PARTY RIGHTS. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -Except as contained in this notice, the name of a copyright holder shall -not be used in advertising or otherwise to promote the sale, use or -other dealings in this Software without prior written authorization of -the copyright holder. - - -Lua-cURLv3 License ------------------------ - -Copyright (c) 2014-2018 Alexey Melnichuk - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to permit -persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. - - -LuaSQLite3 License ------------------------ - -Copyright (C) 2002-2016 Tiago Dionizio, Doug Currie -All rights reserved. -Author : Tiago Dionizio -Author : Doug Currie -Library : lsqlite3 - an SQLite 3 database binding for Lua 5 - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -lua-cjson License ------------------------ - -Copyright (c) 2010-2012 Mark Pulford - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -libc++ and libc++abi License ------------------------ - -These libraries are dual-licensed: - -The University of Illinois/NCSA Open Source License (NCSA) -Developed under the LLVM Project - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal with the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to the -following conditions: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimers. -Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimers in the -documentation and/or other materials provided with the distribution. -Neither the names of , -nor the names of its contributors may be used to endorse or promote -products derived from this Software without specific prior written -permission. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR -ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. - -MIT -Developed under the LLVM Project - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to permit -persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. - - -jemalloc ------------------------ - -Copyright (C) 2002-present Jason Evans . -All rights reserved. -Copyright (C) 2007-2012 Mozilla Foundation. All rights reserved. -Copyright (C) 2009-present Facebook, Inc. All rights reserved. - -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(s), this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice(s), 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 COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. - - -JSON for Modern C++ +CDC File Transfer ----------------------- -Copyright (c) 2013-2018 Niels Lohmann - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to permit -persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT -OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -optional-lite and any-lite -Martin Moene ------------------------ - -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - - -TinyXML-2 ------------------------ - -Copyright (c) 2019-present, Lee Thomason and contributors. - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: +Copyright 2022 Lutz Justen -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. +http://www.apache.org/licenses/LICENSE-2.0 -3. This notice may not be removed or altered from any source -distribution. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/MANIFEST.in b/MANIFEST.in index 301e123..06a2d94 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -5,3 +5,4 @@ include Version include p4test.py include job_trigger.py include tools/*.py +include pyproject.toml diff --git a/P4.py b/P4.py index 5a7c8c0..d605a9a 100755 --- a/P4.py +++ b/P4.py @@ -7,7 +7,7 @@ This uses the Python type P4API.P4Adapter, which is a wrapper for the Perforce ClientApi object. - $Id: //depot/main/p4-python/P4.py#110 $ + $Id: //depot/main/p4-python/P4.py#112 $ #******************************************************************************* # Copyright (c) 2007-2010, Perforce Software, Inc. All rights reserved. @@ -43,30 +43,43 @@ See accompanying LICENSE.txt including for redistribution permission. """ -import sys, datetime +import sys, datetime, time import re import shutil from contextlib import contextmanager import uuid, tempfile import os, os.path, platform import subprocess +import threading # P4Exception - some sort of error occurred class P4Exception(Exception): """Exception thrown by P4 in case of Perforce errors or warnings""" - + def __init__(self, value): - Exception.__init__(self) - + super().__init__(value) if isinstance(value, (list, tuple)) and len(value) > 2: - self.value = value[0] - self.errors = value[1] - self.warnings = value[2] + if len(value[1]) > 0 or len(value[2]) > 0: + self.value = value[0] + self.errors = value[1] + self.warnings = value[2] + else: + self.value = value[0] + self.errors = [re.sub(r'\[.*?\] ', '', str(self.value).split("\n")[0])] + self.warnings = value[2] else: self.value = value def __str__(self): - return str(self.value) + if self.errors: + return str(self.errors[0]) + elif self.warnings: + return str(self.warnings[0]) + else: + return re.sub(r'\[.*?\] ', '', str(self.value).split("\n")[0]) + + def __repr__(self): + return f"{self.__class__.__name__}({str(self)!r})" def __reduce__(self): if hasattr(self, 'errors'): @@ -1103,6 +1116,42 @@ def __check_version(pathToFile): raise Exception("{} must be at least 2015.1, not {}".format(program, version)) raise Exception("Unknown P4 output : {}".format(output) ) + + +class PyKeepAlive: + def __init__(self): + self.__thread = None + self.__alive = 1 + + def isAlive(self): + return self.__alive + + # private member function + def __poll(self): + while True: + if self.isAlive() == 0: + self.__alive = 0 + return 0 + time.sleep(0.5) + + # private member function + def __executeAll(self): + if self.__thread and self.__thread.is_alive(): + pass + + elif self.__thread and not self.__thread.is_alive(): + self.__thread.join() + + else: + self.__thread = threading.Thread(target=self.__poll) + self.__thread.daemon = True + self.__thread.start() + + return self.__alive + + def __call__(self): + return self.__executeAll() + if __name__ == "__main__": p4 = P4() diff --git a/P4API.cpp b/P4API.cpp index 7c258cf..0d1c060 100644 --- a/P4API.cpp +++ b/P4API.cpp @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: //depot/main/p4-python/P4API.cpp#63 $ + * $Id: //depot/main/p4-python/P4API.cpp#64 $ * * Build instructions: * Use Distutils - see accompanying setup.py @@ -57,6 +57,7 @@ #include "PythonMessage.h" #include "PythonTypes.h" #include "debug.h" +#include "PythonKeepAlive.h" // #include @@ -586,6 +587,31 @@ static PyObject * P4Adapter_getTunable(P4Adapter * self, PyObject *args) return NULL; } +// ================== +// ==== SetBreak ==== +// ================== + +static PyObject* P4Adapter_setBreak(P4Adapter* self, PyObject* args) { + PyObject* py_callable; + + // Parse the arguments + if (!PyArg_ParseTuple(args, "O", &py_callable)) { + return NULL; + } + + // Check if the parsed object is callable + if (!PyCallable_Check(py_callable)) { + PyErr_SetString(PyExc_TypeError, "parameter must be callable"); + return NULL; + } + + // Create an object pointer of PythonKeepAlive and pass py_callable + PythonKeepAlive* cb = new PythonKeepAlive(py_callable); + self->clientAPI->SetBreak(cb); + + Py_RETURN_NONE; +} + #if PY_MAJOR_VERSION >= 3 static PyObject * P4Adapter_convert(P4Adapter * self, PyObject *args) @@ -631,6 +657,8 @@ static PyMethodDef P4Adapter_methods[] = { "Sets a tunable to the specified value"}, {"get_tunable", (PyCFunction)P4Adapter_getTunable, METH_VARARGS, "Returns the value for this tunable or 0"}, + {"setbreak", (PyCFunction)P4Adapter_setBreak, METH_VARARGS, + "Set the break callback"}, #if PY_MAJOR_VERSION >= 3 {"__convert", (PyCFunction)P4Adapter_convert, METH_VARARGS, diff --git a/PythonClientAPI.cpp b/PythonClientAPI.cpp index c66cc4f..da10f29 100644 --- a/PythonClientAPI.cpp +++ b/PythonClientAPI.cpp @@ -25,7 +25,7 @@ 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. -$Id: //depot/main/p4-python/PythonClientAPI.cpp#78 $ +$Id: //depot/main/p4-python/PythonClientAPI.cpp#79 $ *******************************************************************************/ #include @@ -1266,3 +1266,12 @@ void PythonClientAPI::RunCmd(const char *cmd, ClientUser *ui, int argc, char * c SetCmdRun(); } + +void PythonClientAPI::SetBreak(PythonKeepAlive* cb) +{ + if( IsConnected() ) { + debug.debug(P4PYDBG_COMMANDS, "[P4] Establish the callback" ); + client.SetBreak(cb); + } + +} diff --git a/PythonClientAPI.h b/PythonClientAPI.h index cef48b6..0e10343 100644 --- a/PythonClientAPI.h +++ b/PythonClientAPI.h @@ -26,7 +26,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: //depot/main/p4-python/PythonClientAPI.h#43 $ + * $Id: //depot/main/p4-python/PythonClientAPI.h#44 $ * * Build instructions: * Use Distutils - see accompanying setup.py @@ -38,6 +38,8 @@ #ifndef PYTHON_CLIENT_API_H #define PYTHON_CLIENT_API_H +#include "PythonKeepAlive.h" + class Enviro; class PythonClientAPI { @@ -232,6 +234,9 @@ class PythonClientAPI void Except( const char *func, Error *e ); void Except( const char *func, const char *msg, const char *cmd ); + // SetBreak + void SetBreak( PythonKeepAlive* cb ); + public: // setter/getter methods and attributes diff --git a/PythonKeepAlive.cpp b/PythonKeepAlive.cpp new file mode 100644 index 0000000..c3993d8 --- /dev/null +++ b/PythonKeepAlive.cpp @@ -0,0 +1,70 @@ +/******************************************************************************* + +Copyright (c) 2024, Perforce Software, Inc. All rights reserved. + +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 COPYRIGHT HOLDERS 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 PERFORCE SOFTWARE, INC. 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. + +*******************************************************************************/ + +/******************************************************************************* + * Name : PythonKeepAlive.cpp + * + * Author : Himanshu Jain + * + * Description : C++ subclass for KeepAlive used by Python KeepAlive. + * Allows Perforce API to implement a customized IsAlive function + * + * $Id: //depot/main/p4-python/PythonKeepAlive.cpp#1 $ + * + ******************************************************************************/ + +#include +#include +#include "PythonThreadGuard.h" +#include "PythonKeepAlive.h" + +PythonKeepAlive::PythonKeepAlive(PyObject* callable) : py_callable(callable) { + // Increment the reference count for the callable + Py_XINCREF(py_callable); +} + +PythonKeepAlive::~PythonKeepAlive() { + // Decrement the reference count for the callable + Py_XDECREF(py_callable); +} + +int PythonKeepAlive::IsAlive() { + + EnsurePythonLock guard; + + if (py_callable && PyCallable_Check(py_callable)) { + PyObject* result = PyObject_CallObject(py_callable, NULL); + if (result != NULL && PyLong_Check(result) && PyLong_AsLong(result) == 0) { + Py_DECREF(result); + return( 0 ); // To terminate the connection + } + + return( 1 ); + } + + return( 1 ); // Default to true if callable is not set or failed +} \ No newline at end of file diff --git a/PythonKeepAlive.h b/PythonKeepAlive.h new file mode 100644 index 0000000..564e879 --- /dev/null +++ b/PythonKeepAlive.h @@ -0,0 +1,46 @@ +/* + * PythonKeepAlive. Subclass of P4::KeepAlive + * + * Copyright (c) 2024, Perforce Software, Inc. All rights reserved. + * + * 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 COPYRIGHT HOLDERS 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 PERFORCE SOFTWARE, INC. 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. + * + * $Id: //depot/main/p4-python/PythonKeepAlive.h#1 $ + * + */ + +#ifndef PYTHON_KEEP_ALIVE_H +#define PYTHON_KEEP_ALIVE_H + +class PythonKeepAlive : public KeepAlive { +public: + PythonKeepAlive(PyObject* callable); + ~PythonKeepAlive(); + + virtual int IsAlive() override; + virtual int PollMs() override { return 0; } + +private: + PyObject* py_callable; +}; + +#endif // PYTHON_KEEP_ALIVE_H \ No newline at end of file diff --git a/RELNOTES.txt b/RELNOTES.txt index 40cdec1..80e6e34 100644 --- a/RELNOTES.txt +++ b/RELNOTES.txt @@ -1,7 +1,7 @@ Release Notes for P4Python, Helix Core API for Python - Version 2023.2 + Version 2024.1 Introduction @@ -23,14 +23,6 @@ Introduction -------------------------------------------------------------------------- -Important End-of-Life Notice - - This major release of P4Python would be the last to provide wheels for and - test against MacOS 10.15. This is part of our commitment to focus on - supported technology platforms. - --------------------------------------------------------------------------- - Installation Installation via pip @@ -114,8 +106,8 @@ Compatibility Statements API Compatibility - This release of P4Python requires at least 2023.2 Perforce API - (2023.2/2519561). Older releases will not compile and are not supported. + This release of P4Python requires at least 2024.1 Perforce API + (2024.1/2596294). Older releases will not compile and are not supported. Python Compatibility @@ -148,8 +140,8 @@ Compatibility Statements Windows (x86, x86_64) Server 2016 - Mac OS X - 10.15, 11, 12 (x86_64) + Mac OS + 11, 12 (x86_64) 12, 13 (ARM64) Linux (x86, x86_64) Ubuntu 20.04, 22.04 @@ -294,6 +286,33 @@ Key to symbols used in change notes below. -------------------------------------------------------------------------- +New functionalities in 2024.1 (2024.1/2625398) (2024/07/17) + + #2603816 (Job #120930) + Built P4Python with P4API 2024.1 (2024.1/2596294) + + #2621458 (Job #115700) + Improved the readability of P4Exception with str(e) and + provided more detailed information in repr(e). + + #2624271 (Job #119953) + Added p4.setbreak(), equivalent to P4API ClientApi::SetBreak(), + to enable P4 command interruption. Use a PyKeepAlive object + with p4.setbreak() to set a callback every 0.5 seconds during + command execution for terminating connections. + +Bugs fixed in 2024.1 (2024.1/2625398) (2024/07/17) + + #2602772 (Job #116089) + Fixed 'SetuptoolsDeprecationWarning: setup.py install is deprecated' + by switching wheel/package installation to 'pip' instead of outdated + 'setup.py install'. + + #2591727 (Job #120437) + RPM packages now includes supported OS version in name string. + +-------------------------------------------------------------------------- + Bugs fixed in 2023.2 Patch 2 (2023.2/2581979) (2024/04/05) #2558218 (Job #094891) diff --git a/SpecMgr.cpp b/SpecMgr.cpp index f7f0477..53f3be9 100644 --- a/SpecMgr.cpp +++ b/SpecMgr.cpp @@ -23,7 +23,7 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - $Id: //depot/main/p4-python/SpecMgr.cpp#56 $ + $Id: //depot/main/p4-python/SpecMgr.cpp#57 $ *******************************************************************************/ /******************************************************************************* @@ -70,7 +70,7 @@ struct specdata { "Description;code:306;type:text;len:128;;" "Options;code:309;type:line;len:32;val:" "unlocked/locked;;" - "View;code:311;type:wlist;words:2;len:64;;" + "View;code:311;fmt:C;type:wlist;words:2;len:64;;" }, { "change", @@ -112,9 +112,9 @@ struct specdata { "StreamAtChange;code:316;type:line;len:64;;" "ServerID;code:315;type:line;ro;len:64;;" "Type;code:318;type:select;len:10;val:" - "writeable/readonly/graph/partitioned;;" + "writeable/readonly/graph/partitioned/partitioned-jnl;;" "Backup;code:319;type:select;len:10;val:enable/disable;;" - "View;code:311;type:wlist;words:2;len:64;;" + "View;code:311;fmt:C;type:wlist;words:2;len:64;;" "ChangeView;code:317;type:llist;len:64;;" }, { @@ -169,7 +169,7 @@ struct specdata { "unlocked/locked,noautoreload/autoreload;;" "Revision;code:312;type:word;words:1;len:64;;" "ServerID;code:315;type:line;ro;len:64;;" - "View;code:311;type:wlist;len:64;;" + "View;code:311;fmt:C;type:wlist;len:64;;" }, { "ldap", @@ -294,7 +294,7 @@ struct specdata { "Name;code:703;rq;type:line;len:32;open:isolate;;" "Parent;code:702;rq;len:64;open:isolate;;" "Type;code:708;rq;type:select;len:32;open:isolate;" - "val:mainline/virtual/development/release/task;;" + "val:mainline/virtual/development/release/task/sparsedev/sparserel;;" "Description;code:709;type:text;len:128;open:isolate;;" "Options;code:707;type:line;len:64;val:" "allsubmit/ownersubmit,unlocked/locked," @@ -315,7 +315,7 @@ struct specdata { }, { "typemap", - "TypeMap;code:601;type:wlist;words:2;len:64;opt:default;z;;" + "TypeMap;code:601;fmt:C;type:wlist;words:2;len:64;opt:default;z;;" }, { "user", diff --git a/Version b/Version index 37e0492..5ee71fd 100644 --- a/Version +++ b/Version @@ -11,7 +11,7 @@ # SUPPDATE = 2010 06 17 ; # Of the build. The copyright date is derived from SUPPDATE. -RELEASE = 2023 2 PREP-TEST_ONLY; -PATCHLEVEL = 2428370 ; -SUPPDATE = 2023 11 27 ; +RELEASE = 2024 1; +PATCHLEVEL = 2603570 ; +SUPPDATE = 2024 05 29 ; diff --git a/build.md b/build.md index 55e510e..4683b96 100644 --- a/build.md +++ b/build.md @@ -1,60 +1,57 @@ ## Building P4Python from Source - 1. Download the corresponding Perforce C++ API (e.g. if you trying to build P4Python 2023.1, download the r23.1 P4API) from + 1. Download the corresponding Perforce C++ API (e.g. if you trying to build P4Python 2023.1, download the r23.1 P4API) from https://ftp.perforce.com/perforce. The API archive is located in release and platform-specific subdirectories. - Under Linux, the p4api is named _p4api-glib\-openssl\.tgz_ - - Note that setup.py will download the correct p4api automatically from - https://ftp.perforce.com/perforce if you do not provide an\ - _--apidir_ parameter to the "setup.py build" command. + Under Linux, the p4api is named _p4api-glib\-openssl\.tgz_ + + Note that pip will download the correct p4api automatically from + https://ftp.perforce.com/perforce if you do not set + _apidir_ environment variable. - Mac OS X users should get the API from the relevant platform directory e.g. - "**bin.macosx1015x86_64**" or "**bin.macosx12arm64**".\ - The p4api is named _p4api-openssl\.tgz_ + Mac OS X users should get the API from the relevant platform directory e.g. + "**bin.macosx1015x86_64**" or "**bin.macosx12arm64**".\ + The p4api is named _p4api-openssl\.tgz_ - Under Windows the p4api needs to match your compiler, build type (static - or dynamic) and SSL version. for instance: - "**p4api_vs2019_static_openssl3.zip**" or "**p4api_vs2019_dyn_openssl3.zip**" + Under Windows the p4api needs to match your compiler, build type (static + or dynamic) and SSL version. For instance: + "**p4api_vs2019_static_openssl3.zip**" or "**p4api_vs2019_dyn_openssl3.zip**" - **Note:** 32-bit builds of P4Python require a 32-bit version of the - C++ API and a 32-bit version of Python. 64-bit builds of - P4Python require a 64-bit version of the C++ API and a - 64-bit version of Python. - - Unzip the archive into an empty directory. + **Note:** 64-bit builds of P4Python require a 64-bit version of the C++ API and + a 64-bit version of Python. + + Unzip the archive into an empty directory. - 4. Download the P4Python source code from this repository or https://ftp.perforce.com \ - (e.g. for release 2023.1, source code can be found at https://ftp.perforce.com/perforce/r23.1/bin.tools/) \ + 2. Download the P4Python source code from this repository or https://ftp.perforce.com + (e.g. for release 2023.1, source code can be found at https://ftp.perforce.com/perforce/r23.1/bin.tools/) extract the archive into a new empty directory. - 7. If needed, install the Openssl libraries. - - 8. To build P4Python, execute setup.py in P4Python source directory, with the following arguments: + 3. If needed, install the Openssl libraries. - ``` - python3 setup.py build --apidir --ssl - ``` - - **Note:** In order to cleanly reinstall P4Python, remove the directory named "build". + 4. Set apidir and ssl environment variable with values as their absolute path: + + ``` + export apidir= + export ssl= + ``` + + 5. To install P4Python, execute the following command from P4Python source code directory: + + ``` + python3 -m pip install . + ``` + **Note:** In order to cleanly reinstall P4Python, remove the directory named "build". - 10. To test your P4Python build, excecute p4test.py: + 6. To test your P4Python install, execute p4test.py: ``` python3 p4test.py ``` **Note:** This test requires the Perforce server executable p4d 17.1 or better to be installed and in the PATH. - 12. To install P4Python, execute the following command: - - ``` - python3 setup.py install - ``` - + 7. To build P4Python wheel, execute the following command: - If this doesn't work, you may need to build and install in the same command: - ``` - python3 setup.py build --apidir --ssl install + python3 -m pip wheel . -w dist ``` **Note:** On Unix/Mac platforms, the installation must be performed @@ -72,12 +69,12 @@ Perforce Server 2012.1 and later supports SSL connections and the C++ API has been compiled with this support. With 2020.1 SSL support is mandatory, that is, P4Python must be linked with valid OpenSSL libraries. -To specify which SSL library to use, provide the --ssl \ -switch to the build. Without this setup will attempt to run -"openssl version" to identify the location of the library path for -openssl and whether openssl has an appropriate version to link to. +To specify which SSL library to use, set enviroment variable +ssl=\ switch to the build. Without this setup +will attempt to run "openssl version" to identify the location of +the library path for openssl and whether openssl has an appropriate +version to link to. If on linux, and the build process cannot find the correct openssl -libraries, and the -ssl option was not used, then the openssl source will -be downloaded, compiled and installed (this will require a superuser +libraries, and the ssl environment variable was not used, then the openssl source will be downloaded, compiled and installed (this will require a superuser password for the installation) diff --git a/linux_build/build-wheels.sh b/linux_build/build-wheels.sh index eb3663a..eb8586d 100755 --- a/linux_build/build-wheels.sh +++ b/linux_build/build-wheels.sh @@ -19,14 +19,9 @@ mkdir -p repair for VERSION in $1; do PYBIN="/opt/python/$(ls /opt/python/ | grep cp$VERSION | grep -v 27mu)/bin" - ## Make tgz - "${PYBIN}/python" setup.py build_ext --apidir $P4API --ssl /openssl/lib sdist --formats=gztar --keep-temp - - ## Make object files for installer - "${PYBIN}/python" setup.py build --apidir $P4API --ssl /openssl/lib - - ## Build the installer - "${PYBIN}/python" setup.py build_ext --apidir $P4API --ssl /openssl/lib bdist_wheel + ## Set env path for apidir and ssl directories + export apidir=$P4API + export ssl=/openssl/lib ## Upgrade pip "${PYBIN}/python" -m pip install --upgrade pip @@ -34,6 +29,9 @@ for VERSION in $1; do #Install wheel module "${PYBIN}/python" -m pip install wheel + ## Build the installer + "${PYBIN}/python" -m pip wheel . -w dist -v + # Install the wheel "${PYBIN}/python" -m pip install /work/p4-python/dist/$(ls /work/p4-python/dist/ | grep $VERSION | grep \.whl) diff --git a/p4test.py b/p4test.py index 215e60c..df80962 100644 --- a/p4test.py +++ b/p4test.py @@ -1383,13 +1383,8 @@ def testEvilTwin(self): except Exception as e: error = str(e) - results = ''.join([i for i in error if not i.isdigit()]) - expected = "\t[Error]: \"Merges still pending -- use 'resolve' to merge files.\\nSubmit failed -- fix problems above then use 'p submit -c '.\"" - - for item in results.split("\n"): - if "[Error]:" in item: - result = item - + result = ''.join([i for i in error if not i.isdigit()]) + expected = "Merges still pending -- use 'resolve' to merge files.\nSubmit failed -- fix problems above then use 'p submit -c '." self.assertEqual(result, expected) def testLockedClientRemoval(self): @@ -1411,6 +1406,58 @@ def testLockedClientRemoval(self): self.p4.save_client(lockedClient) with self.p4.temp_client("temp", "LockedClient"): self.p4.run_info() + + def testSetbreak( self ): + testDir = 'test_setbreak' + testAbsoluteDir = os.path.join(self.client_root, testDir) + os.mkdir(testAbsoluteDir) + + self.p4.connect() + self.assertTrue(self.p4.connected(), "Not connected") + self._setClient() + + # create the file for testing setbreak + class MyKeepAlive(P4.PyKeepAlive): + def __init__(self, total_count): + P4.PyKeepAlive.__init__(self) + self.counter = 0 + self.total_count = total_count + + def isAlive(self): + self.counter += 1 + if self.counter > self.total_count: + return 0 + return 1 + + #create a multiple changelist revision + for i in range(100): + file = "foo" + str(i) + fname = os.path.join(testAbsoluteDir, file) + line = "This is a test line to create a test file.\n" + with open(fname, 'w') as file: + file.write(line) + testFile = str(fname) + self.p4.run_add(testFile) + + change = self.p4.fetch_change() + change._description = "Initial changes" + self.p4.run_submit(change) + + ka = MyKeepAlive(total_count=0) + self.p4.setbreak(ka) + total_files = len(self.p4.run("changes")) + self.assertGreater(100, total_files, "Setbreak is not working") + self.p4.disconnect() + + self.p4.connect() + self.assertTrue(self.p4.connected(), "Not connected") + ka = MyKeepAlive(total_count=50) + self.p4.setbreak(ka) + total_files = len(self.p4.run("changes")) + self.assertEqual(100, total_files, "Setbreak is not working") + self.p4.disconnect() + + if __name__ == '__main__': unittest.main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..e69de29 diff --git a/setup.py b/setup.py index 34fe6d8..f642ecc 100644 --- a/setup.py +++ b/setup.py @@ -99,7 +99,8 @@ class p4build(build_module): ] def initialize_options(self, *args, **kwargs): - self.ssl = self.apidir = None + self.apidir = os.getenv("apidir", None) + self.ssl = os.getenv("ssl", None) build_module.initialize_options(self, *args, **kwargs) def finalize_options(self): @@ -123,7 +124,8 @@ class p4build_ext(build_ext_module): ] def initialize_options(self, *args, **kwargs): - self.ssl = self.apidir = None + self.apidir = os.getenv("apidir", None) + self.ssl = os.getenv("ssl", None) build_ext_module.initialize_options(self, *args, **kwargs) def get_config(self, option): @@ -420,7 +422,7 @@ def do_setup(): "PythonMergeData.cpp", "P4MapMaker.cpp", "PythonSpecData.cpp", "PythonMessage.cpp", "PythonActionMergeData.cpp", "PythonClientProgress.cpp", - "P4PythonDebug.cpp"], + "P4PythonDebug.cpp", "PythonKeepAlive.cpp"], include_dirs=[], library_dirs=[], libraries=[],