##// END OF EJS Templates
inno: script to automate building Inno installer...
inno: script to automate building Inno installer The official Inno installer build process is poorly documented. And attempting to reproduce behavior of the installer uploaded to www.mercurial-scm.org has revealed a number of unexpected behaviors. This commit attempts to improve the state of reproducibility of the Inno installer by introducing a Python script to largely automate the building of the installer. The new script (which must be run from an environment with the Visual C++ environment configured) takes care of producing an Inno installer. When run from a fresh Mercurial source checkout with all the proper system dependencies (the VC++ toolchain, Windows 10 SDK, and Inno tools) installed, it "just works." The script takes care of downloading all the Python dependencies in a secure manner and manages the build environment for you. You don't need any additional config files: just launch the script, pointing it at an existing Python and ISCC binary and it takes care of the rest. The produced installer creates a Mercurial installation with a handful of differences from the existing 4.9 installers (produced by someone else): * add_path.exe is missing (this was removed a few changesets ago) * The set of api-ms-win-core-* DLLs is different (I suspect this is due to me using a different UCRT / Windows version). * kernelbase.dll and msasn1.dll are missing. * There are a different set of .pyc files for dulwich, keyring, and pygments due to us using the latest versions of each. * We include Tcl/Tk DLLs and .pyc files (I'm not sure why these are missing from the existing installers). * We include the urllib3 and win32ctypes packages (which are dependencies of dulwich and pywin32, respectively). I'm not sure why these aren't present in the existing installers. * We include a different set of files for the distutils package. I'm not sure why. But it should be harmless. * We include the docutils package (it is getting picked up as a dependency somehow). I think this is fine. * We include a copy of argparse.pyc. I'm not sure why this was missing from existing installers. * We don't have a copy of sqlite3/dump.pyc. I'm not sure why. The SQLite C extension code only imports this module when conn.iterdump() is called. It should be safe to omit. * We include files in the email.test and test packages. The set of files is small and their presence should be harmless. The new script and support code is written in Python 3 because it is brand new and independent code and I don't believe new Python projects should be using Python 2 in 2019 if they have a choice about it. The readme.txt file has been renamed to readme.rst and overhauled to reflect the existence of build.py. Differential Revision: https://phab.mercurial-scm.org/D6066

File last commit:

r40157:73fef626 default
r42019:d7dc4ac1 default
Show More
compressobj.c
256 lines | 6.6 KiB | text/x-c | CLexer
/**
* Copyright (c) 2016-present, Gregory Szorc
* All rights reserved.
*
* This software may be modified and distributed under the terms
* of the BSD license. See the LICENSE file for details.
*/
#include "python-zstandard.h"
extern PyObject* ZstdError;
PyDoc_STRVAR(ZstdCompressionObj__doc__,
"Perform compression using a standard library compatible API.\n"
);
static void ZstdCompressionObj_dealloc(ZstdCompressionObj* self) {
PyMem_Free(self->output.dst);
self->output.dst = NULL;
Py_XDECREF(self->compressor);
PyObject_Del(self);
}
static PyObject* ZstdCompressionObj_compress(ZstdCompressionObj* self, PyObject* args, PyObject* kwargs) {
static char* kwlist[] = {
"data",
NULL
};
Py_buffer source;
ZSTD_inBuffer input;
size_t zresult;
PyObject* result = NULL;
Py_ssize_t resultSize = 0;
if (self->finished) {
PyErr_SetString(ZstdError, "cannot call compress() after compressor finished");
return NULL;
}
#if PY_MAJOR_VERSION >= 3
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*:compress",
#else
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s*:compress",
#endif
kwlist, &source)) {
return NULL;
}
if (!PyBuffer_IsContiguous(&source, 'C') || source.ndim > 1) {
PyErr_SetString(PyExc_ValueError,
"data buffer should be contiguous and have at most one dimension");
goto finally;
}
input.src = source.buf;
input.size = source.len;
input.pos = 0;
while ((ssize_t)input.pos < source.len) {
Py_BEGIN_ALLOW_THREADS
zresult = ZSTD_compress_generic(self->compressor->cctx, &self->output,
&input, ZSTD_e_continue);
Py_END_ALLOW_THREADS
if (ZSTD_isError(zresult)) {
PyErr_Format(ZstdError, "zstd compress error: %s", ZSTD_getErrorName(zresult));
Py_CLEAR(result);
goto finally;
}
if (self->output.pos) {
if (result) {
resultSize = PyBytes_GET_SIZE(result);
if (safe_pybytes_resize(&result, resultSize + self->output.pos)) {
Py_CLEAR(result);
goto finally;
}
memcpy(PyBytes_AS_STRING(result) + resultSize,
self->output.dst, self->output.pos);
}
else {
result = PyBytes_FromStringAndSize(self->output.dst, self->output.pos);
if (!result) {
goto finally;
}
}
self->output.pos = 0;
}
}
if (NULL == result) {
result = PyBytes_FromString("");
}
finally:
PyBuffer_Release(&source);
return result;
}
static PyObject* ZstdCompressionObj_flush(ZstdCompressionObj* self, PyObject* args, PyObject* kwargs) {
static char* kwlist[] = {
"flush_mode",
NULL
};
int flushMode = compressorobj_flush_finish;
size_t zresult;
PyObject* result = NULL;
Py_ssize_t resultSize = 0;
ZSTD_inBuffer input;
ZSTD_EndDirective zFlushMode;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:flush", kwlist, &flushMode)) {
return NULL;
}
if (flushMode != compressorobj_flush_finish && flushMode != compressorobj_flush_block) {
PyErr_SetString(PyExc_ValueError, "flush mode not recognized");
return NULL;
}
if (self->finished) {
PyErr_SetString(ZstdError, "compressor object already finished");
return NULL;
}
switch (flushMode) {
case compressorobj_flush_block:
zFlushMode = ZSTD_e_flush;
break;
case compressorobj_flush_finish:
zFlushMode = ZSTD_e_end;
self->finished = 1;
break;
default:
PyErr_SetString(ZstdError, "unhandled flush mode");
return NULL;
}
assert(self->output.pos == 0);
input.src = NULL;
input.size = 0;
input.pos = 0;
while (1) {
Py_BEGIN_ALLOW_THREADS
zresult = ZSTD_compress_generic(self->compressor->cctx, &self->output,
&input, zFlushMode);
Py_END_ALLOW_THREADS
if (ZSTD_isError(zresult)) {
PyErr_Format(ZstdError, "error ending compression stream: %s",
ZSTD_getErrorName(zresult));
return NULL;
}
if (self->output.pos) {
if (result) {
resultSize = PyBytes_GET_SIZE(result);
if (safe_pybytes_resize(&result, resultSize + self->output.pos)) {
Py_XDECREF(result);
return NULL;
}
memcpy(PyBytes_AS_STRING(result) + resultSize,
self->output.dst, self->output.pos);
}
else {
result = PyBytes_FromStringAndSize(self->output.dst, self->output.pos);
if (!result) {
return NULL;
}
}
self->output.pos = 0;
}
if (!zresult) {
break;
}
}
if (result) {
return result;
}
else {
return PyBytes_FromString("");
}
}
static PyMethodDef ZstdCompressionObj_methods[] = {
{ "compress", (PyCFunction)ZstdCompressionObj_compress, METH_VARARGS | METH_KEYWORDS,
PyDoc_STR("compress data") },
{ "flush", (PyCFunction)ZstdCompressionObj_flush, METH_VARARGS | METH_KEYWORDS,
PyDoc_STR("finish compression operation") },
{ NULL, NULL }
};
PyTypeObject ZstdCompressionObjType = {
PyVarObject_HEAD_INIT(NULL, 0)
"zstd.ZstdCompressionObj", /* tp_name */
sizeof(ZstdCompressionObj), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)ZstdCompressionObj_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
ZstdCompressionObj__doc__, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
ZstdCompressionObj_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
};
void compressobj_module_init(PyObject* module) {
Py_TYPE(&ZstdCompressionObjType) = &PyType_Type;
if (PyType_Ready(&ZstdCompressionObjType) < 0) {
return;
}
}