sapling/cstore/pythonutil.cpp
Wez Furlong f02ec48128 treemanifest: ConstantStringRef -> shared_ptr<string>
Summary:
this simplifies the code and resolves a `new[]/delete`
allocator/deallocator mismatch that I tripped over in D4929693

I think this is pretty straight forward.  The diff is made a little
larger than I would have liked because there were some missing `const`
qualifiers that had to be propagated out to various callers.

Test Plan:
ran the tests:

```
11:23 $ rt
.................................s.........s.s.s......s..sss............s.....s...................................................................................................................
Skipped test-p4fastimport-import-incremental.t: missing feature: Perforce server and client
Skipped test-p4fastimport-criss-cross.t: missing feature: Perforce server and client
Skipped test-p4fastimport-case-insensitive-rename.t: missing feature: Perforce server and client
Skipped test-p4fastimport-import-modes.t: missing feature: Perforce server and client
Skipped test-p4fastimport-import.t: missing feature: Perforce server and client
Skipped test-p4fastimport-import-deletes.t: missing feature: Perforce server and client
Skipped test-p4fastimport-case-insensitivity.t: missing feature: Perforce server and client
Skipped test-p4fastimport-import-parallel.t: missing feature: Perforce server and client
Skipped test-infinitepush-backup-sql.t: missing getdb.sh
Skipped test-infinitepush-sql.t: missing getdb.sh
# Ran 184 tests, 10 skipped, 0 warned, 0 failed.
```

Reviewers: simpkins, durham

Reviewed By: durham

Subscribers: net-systems-diffs@fb.com, mjpieters, #mercurial

Differential Revision: https://phabricator.intern.facebook.com/D4930821

Signature: t1:4930821:1493160075:5ee1d452b394c4d6f347029b0ff3fd89377624c5
2017-04-25 15:44:55 -07:00

172 lines
4.6 KiB
C++

// pythonutil.cpp - utilities to glue C++ code to python
//
// Copyright 2016 Facebook, Inc.
//
// This software may be used and distributed according to the terms of the
// GNU General Public License version 2 or any later version.
//
// no-check-code
#include "pythonutil.h"
PythonObj::PythonObj() :
obj(NULL) {
}
PythonObj::PythonObj(PyObject *obj) {
if (!obj) {
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_RuntimeError,
"attempted to construct null PythonObj");
}
throw pyexception();
}
this->obj = obj;
}
PythonObj::PythonObj(const PythonObj& other) {
this->obj = other.obj;
Py_XINCREF(this->obj);
}
PythonObj::~PythonObj() {
Py_XDECREF(this->obj);
}
PythonObj& PythonObj::operator=(const PythonObj &other) {
Py_XDECREF(this->obj);
this->obj = other.obj;
Py_XINCREF(this->obj);
return *this;
}
PythonObj::operator PyObject* () const {
return this->obj;
}
PythonObj::operator bool() const {
return this->obj != NULL;
}
/**
* Function used to obtain a return value that will persist beyond the life
* of the PythonObj. This is useful for returning objects to Python C apis
* and letting them manage the remaining lifetime of the object.
*/
PyObject *PythonObj::returnval() {
Py_XINCREF(this->obj);
return this->obj;
}
/**
* Invokes getattr to retrieve the attribute from the python object.
*/
PythonObj PythonObj::getattr(const char *name) {
return PyObject_GetAttrString(this->obj, name);
}
/**
* Executes the current callable object if it's callable.
*/
PythonObj PythonObj::call(const PythonObj &args) {
PyObject *result = PyEval_CallObject(this->obj, args);
return PythonObj(result);
}
/**
* Invokes the specified method on this instance.
*/
PythonObj PythonObj::callmethod(const char *name, const PythonObj &args) {
PythonObj function = this->getattr(name);
return PyObject_CallObject(function, args);
}
PythonStore::PythonStore(PythonObj store) :
_get(store.getattr("get")),
_storeObj(store) {
}
PythonStore::PythonStore(const PythonStore &store) :
_get(store._get),
_storeObj(store._storeObj) {
}
ConstantStringRef PythonStore::get(const Key &key) {
PythonObj arglist = Py_BuildValue("s#s#",
key.name.c_str(), (Py_ssize_t)key.name.size(),
key.node, (Py_ssize_t)BIN_NODE_SIZE);
PyObject *result = PyEval_CallObject(_get, arglist);
if (!result) {
if (PyErr_Occurred()) {
throw pyexception();
}
PyErr_Format(PyExc_RuntimeError,
"unable to find tree '%.*s:...'", (int) key.name.size(), key.name.c_str());
throw pyexception();
}
PythonObj resultobj(result);
char *path;
Py_ssize_t pathlen;
if (PyString_AsStringAndSize((PyObject*)result, &path, &pathlen)) {
throw pyexception();
}
return ConstantStringRef(path, pathlen);
}
bool PythonMatcher::matches(const std::string &path) {
PythonObj matchArgs = Py_BuildValue("(s#)", path.c_str(), (Py_ssize_t)path.size());
PythonObj matched = this->_matcherObj.call(matchArgs);
return PyObject_IsTrue(matched) == 1;
}
bool PythonMatcher::matches(const char *path, const size_t pathlen) {
PythonObj matchArgs = Py_BuildValue("(s#)", path, (Py_ssize_t)pathlen);
PythonObj matched = this->_matcherObj.call(matchArgs);
return PyObject_IsTrue(matched) == 1;
}
bool PythonMatcher::visitdir(const std::string &path) {
Py_ssize_t size = path.size();
if (size > 1 && path[size - 1] == '/') {
size--;
}
PythonObj matchArgs = Py_BuildValue("(s#)", path.c_str(), (Py_ssize_t)size);
PythonObj matched = this->_matcherObj.callmethod("visitdir", matchArgs);
return PyObject_IsTrue(matched) == 1;
}
void PythonDiffResult::add(const std::string &path,
const char *beforeNode, const char *beforeFlag,
const char *afterNode, const char *afterFlag) {
Py_ssize_t beforeLen = beforeNode != NULL ? BIN_NODE_SIZE : 0;
Py_ssize_t afterLen = afterNode != NULL ? BIN_NODE_SIZE : 0;
PythonObj entry = Py_BuildValue(
"((s#s#)(s#s#))",
beforeNode, beforeLen,
(beforeFlag == NULL) ? MAGIC_EMPTY_STRING : beforeFlag, Py_ssize_t(beforeFlag ? 1 : 0),
afterNode, afterLen,
(afterFlag == NULL) ? MAGIC_EMPTY_STRING : afterFlag, Py_ssize_t(afterFlag ? 1 : 0));
PythonObj pathObj = PyString_FromStringAndSize(path.c_str(), path.length());
if (PyDict_SetItem(this->_diff, pathObj, entry)) {
throw pyexception();
}
}
void PythonDiffResult::addclean(const std::string &path) {
PythonObj pathObj = PyString_FromStringAndSize(path.c_str(), path.length());
Py_INCREF(Py_None);
if (PyDict_SetItem(this->_diff, pathObj, Py_None)) {
throw pyexception();
}
}