mirror of https://github.com/python/cpython
gh-104773: Remove the msilib package (GH-104911)
This commit is contained in:
parent
41768a2bd3
commit
98c4333e88
|
@ -1,565 +0,0 @@
|
|||
:mod:`msilib` --- Read and write Microsoft Installer files
|
||||
==========================================================
|
||||
|
||||
.. module:: msilib
|
||||
:platform: Windows
|
||||
:synopsis: Creation of Microsoft Installer files, and CAB files.
|
||||
:deprecated:
|
||||
|
||||
.. moduleauthor:: Martin v. Löwis <martin@v.loewis.de>
|
||||
.. sectionauthor:: Martin v. Löwis <martin@v.loewis.de>
|
||||
|
||||
**Source code:** :source:`Lib/msilib/__init__.py`
|
||||
|
||||
.. index:: single: msi
|
||||
|
||||
.. deprecated-removed:: 3.11 3.13
|
||||
The :mod:`msilib` module is deprecated
|
||||
(see :pep:`PEP 594 <594#msilib>` for details).
|
||||
|
||||
--------------
|
||||
|
||||
The :mod:`msilib` supports the creation of Microsoft Installer (``.msi``) files.
|
||||
Because these files often contain an embedded "cabinet" file (``.cab``), it also
|
||||
exposes an API to create CAB files. Support for reading ``.cab`` files is
|
||||
currently not implemented; read support for the ``.msi`` database is possible.
|
||||
|
||||
This package aims to provide complete access to all tables in an ``.msi`` file,
|
||||
therefore, it is a fairly low-level API. One primary application of this
|
||||
package is the creation of Python installer package itself (although that currently
|
||||
uses a different version of ``msilib``).
|
||||
|
||||
The package contents can be roughly split into four parts: low-level CAB
|
||||
routines, low-level MSI routines, higher-level MSI routines, and standard table
|
||||
structures.
|
||||
|
||||
|
||||
.. function:: FCICreate(cabname, files)
|
||||
|
||||
Create a new CAB file named *cabname*. *files* must be a list of tuples, each
|
||||
containing the name of the file on disk, and the name of the file inside the CAB
|
||||
file.
|
||||
|
||||
The files are added to the CAB file in the order they appear in the list. All
|
||||
files are added into a single CAB file, using the MSZIP compression algorithm.
|
||||
|
||||
Callbacks to Python for the various steps of MSI creation are currently not
|
||||
exposed.
|
||||
|
||||
|
||||
.. function:: UuidCreate()
|
||||
|
||||
Return the string representation of a new unique identifier. This wraps the
|
||||
Windows API functions :c:func:`UuidCreate` and :c:func:`UuidToString`.
|
||||
|
||||
|
||||
.. function:: OpenDatabase(path, persist)
|
||||
|
||||
Return a new database object by calling MsiOpenDatabase. *path* is the file
|
||||
name of the MSI file; *persist* can be one of the constants
|
||||
``MSIDBOPEN_CREATEDIRECT``, ``MSIDBOPEN_CREATE``, ``MSIDBOPEN_DIRECT``,
|
||||
``MSIDBOPEN_READONLY``, or ``MSIDBOPEN_TRANSACT``, and may include the flag
|
||||
``MSIDBOPEN_PATCHFILE``. See the Microsoft documentation for the meaning of
|
||||
these flags; depending on the flags, an existing database is opened, or a new
|
||||
one created.
|
||||
|
||||
|
||||
.. function:: CreateRecord(count)
|
||||
|
||||
Return a new record object by calling :c:func:`MSICreateRecord`. *count* is the
|
||||
number of fields of the record.
|
||||
|
||||
|
||||
.. function:: init_database(name, schema, ProductName, ProductCode, ProductVersion, Manufacturer)
|
||||
|
||||
Create and return a new database *name*, initialize it with *schema*, and set
|
||||
the properties *ProductName*, *ProductCode*, *ProductVersion*, and
|
||||
*Manufacturer*.
|
||||
|
||||
*schema* must be a module object containing ``tables`` and
|
||||
``_Validation_records`` attributes; typically, :mod:`msilib.schema` should be
|
||||
used.
|
||||
|
||||
The database will contain just the schema and the validation records when this
|
||||
function returns.
|
||||
|
||||
|
||||
.. function:: add_data(database, table, records)
|
||||
|
||||
Add all *records* to the table named *table* in *database*.
|
||||
|
||||
The *table* argument must be one of the predefined tables in the MSI schema,
|
||||
e.g. ``'Feature'``, ``'File'``, ``'Component'``, ``'Dialog'``, ``'Control'``,
|
||||
etc.
|
||||
|
||||
*records* should be a list of tuples, each one containing all fields of a
|
||||
record according to the schema of the table. For optional fields,
|
||||
``None`` can be passed.
|
||||
|
||||
Field values can be ints, strings, or instances of the Binary class.
|
||||
|
||||
|
||||
.. class:: Binary(filename)
|
||||
|
||||
Represents entries in the Binary table; inserting such an object using
|
||||
:func:`add_data` reads the file named *filename* into the table.
|
||||
|
||||
|
||||
.. function:: add_tables(database, module)
|
||||
|
||||
Add all table content from *module* to *database*. *module* must contain an
|
||||
attribute *tables* listing all tables for which content should be added, and one
|
||||
attribute per table that has the actual content.
|
||||
|
||||
This is typically used to install the sequence tables.
|
||||
|
||||
|
||||
.. function:: add_stream(database, name, path)
|
||||
|
||||
Add the file *path* into the ``_Stream`` table of *database*, with the stream
|
||||
name *name*.
|
||||
|
||||
|
||||
.. function:: gen_uuid()
|
||||
|
||||
Return a new UUID, in the format that MSI typically requires (i.e. in curly
|
||||
braces, and with all hexdigits in uppercase).
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
||||
`FCICreate <https://msdn.microsoft.com/en-us/library/bb432265.aspx>`_
|
||||
`UuidCreate <https://msdn.microsoft.com/en-us/library/windows/desktop/aa379205.aspx>`_
|
||||
`UuidToString <https://msdn.microsoft.com/en-us/library/windows/desktop/aa379352.aspx>`_
|
||||
|
||||
.. _database-objects:
|
||||
|
||||
Database Objects
|
||||
----------------
|
||||
|
||||
|
||||
.. method:: Database.OpenView(sql)
|
||||
|
||||
Return a view object, by calling :c:func:`MSIDatabaseOpenView`. *sql* is the SQL
|
||||
statement to execute.
|
||||
|
||||
|
||||
.. method:: Database.Commit()
|
||||
|
||||
Commit the changes pending in the current transaction, by calling
|
||||
:c:func:`MSIDatabaseCommit`.
|
||||
|
||||
|
||||
.. method:: Database.GetSummaryInformation(count)
|
||||
|
||||
Return a new summary information object, by calling
|
||||
:c:func:`MsiGetSummaryInformation`. *count* is the maximum number of updated
|
||||
values.
|
||||
|
||||
.. method:: Database.Close()
|
||||
|
||||
Close the database object, through :c:func:`MsiCloseHandle`.
|
||||
|
||||
.. versionadded:: 3.7
|
||||
|
||||
.. seealso::
|
||||
|
||||
`MSIDatabaseOpenView <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370082.aspx>`_
|
||||
`MSIDatabaseCommit <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370075.aspx>`_
|
||||
`MSIGetSummaryInformation <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370301.aspx>`_
|
||||
`MsiCloseHandle <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370067.aspx>`_
|
||||
|
||||
.. _view-objects:
|
||||
|
||||
View Objects
|
||||
------------
|
||||
|
||||
|
||||
.. method:: View.Execute(params)
|
||||
|
||||
Execute the SQL query of the view, through :c:func:`MSIViewExecute`. If
|
||||
*params* is not ``None``, it is a record describing actual values of the
|
||||
parameter tokens in the query.
|
||||
|
||||
|
||||
.. method:: View.GetColumnInfo(kind)
|
||||
|
||||
Return a record describing the columns of the view, through calling
|
||||
:c:func:`MsiViewGetColumnInfo`. *kind* can be either ``MSICOLINFO_NAMES`` or
|
||||
``MSICOLINFO_TYPES``.
|
||||
|
||||
|
||||
.. method:: View.Fetch()
|
||||
|
||||
Return a result record of the query, through calling :c:func:`MsiViewFetch`.
|
||||
|
||||
|
||||
.. method:: View.Modify(kind, data)
|
||||
|
||||
Modify the view, by calling :c:func:`MsiViewModify`. *kind* can be one of
|
||||
``MSIMODIFY_SEEK``, ``MSIMODIFY_REFRESH``, ``MSIMODIFY_INSERT``,
|
||||
``MSIMODIFY_UPDATE``, ``MSIMODIFY_ASSIGN``, ``MSIMODIFY_REPLACE``,
|
||||
``MSIMODIFY_MERGE``, ``MSIMODIFY_DELETE``, ``MSIMODIFY_INSERT_TEMPORARY``,
|
||||
``MSIMODIFY_VALIDATE``, ``MSIMODIFY_VALIDATE_NEW``,
|
||||
``MSIMODIFY_VALIDATE_FIELD``, or ``MSIMODIFY_VALIDATE_DELETE``.
|
||||
|
||||
*data* must be a record describing the new data.
|
||||
|
||||
|
||||
.. method:: View.Close()
|
||||
|
||||
Close the view, through :c:func:`MsiViewClose`.
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
||||
`MsiViewExecute <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370513.aspx>`_
|
||||
`MSIViewGetColumnInfo <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370516.aspx>`_
|
||||
`MsiViewFetch <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370514.aspx>`_
|
||||
`MsiViewModify <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370519.aspx>`_
|
||||
`MsiViewClose <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370510.aspx>`_
|
||||
|
||||
.. _summary-objects:
|
||||
|
||||
Summary Information Objects
|
||||
---------------------------
|
||||
|
||||
|
||||
.. method:: SummaryInformation.GetProperty(field)
|
||||
|
||||
Return a property of the summary, through :c:func:`MsiSummaryInfoGetProperty`.
|
||||
*field* is the name of the property, and can be one of the constants
|
||||
``PID_CODEPAGE``, ``PID_TITLE``, ``PID_SUBJECT``, ``PID_AUTHOR``,
|
||||
``PID_KEYWORDS``, ``PID_COMMENTS``, ``PID_TEMPLATE``, ``PID_LASTAUTHOR``,
|
||||
``PID_REVNUMBER``, ``PID_LASTPRINTED``, ``PID_CREATE_DTM``,
|
||||
``PID_LASTSAVE_DTM``, ``PID_PAGECOUNT``, ``PID_WORDCOUNT``, ``PID_CHARCOUNT``,
|
||||
``PID_APPNAME``, or ``PID_SECURITY``.
|
||||
|
||||
|
||||
.. method:: SummaryInformation.GetPropertyCount()
|
||||
|
||||
Return the number of summary properties, through
|
||||
:c:func:`MsiSummaryInfoGetPropertyCount`.
|
||||
|
||||
|
||||
.. method:: SummaryInformation.SetProperty(field, value)
|
||||
|
||||
Set a property through :c:func:`MsiSummaryInfoSetProperty`. *field* can have the
|
||||
same values as in :meth:`GetProperty`, *value* is the new value of the property.
|
||||
Possible value types are integer and string.
|
||||
|
||||
|
||||
.. method:: SummaryInformation.Persist()
|
||||
|
||||
Write the modified properties to the summary information stream, using
|
||||
:c:func:`MsiSummaryInfoPersist`.
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
||||
`MsiSummaryInfoGetProperty <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370409.aspx>`_
|
||||
`MsiSummaryInfoGetPropertyCount <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370488.aspx>`_
|
||||
`MsiSummaryInfoSetProperty <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370491.aspx>`_
|
||||
`MsiSummaryInfoPersist <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370490.aspx>`_
|
||||
|
||||
.. _record-objects:
|
||||
|
||||
Record Objects
|
||||
--------------
|
||||
|
||||
|
||||
.. method:: Record.GetFieldCount()
|
||||
|
||||
Return the number of fields of the record, through
|
||||
:c:func:`MsiRecordGetFieldCount`.
|
||||
|
||||
|
||||
.. method:: Record.GetInteger(field)
|
||||
|
||||
Return the value of *field* as an integer where possible. *field* must
|
||||
be an integer.
|
||||
|
||||
|
||||
.. method:: Record.GetString(field)
|
||||
|
||||
Return the value of *field* as a string where possible. *field* must
|
||||
be an integer.
|
||||
|
||||
|
||||
.. method:: Record.SetString(field, value)
|
||||
|
||||
Set *field* to *value* through :c:func:`MsiRecordSetString`. *field* must be an
|
||||
integer; *value* a string.
|
||||
|
||||
|
||||
.. method:: Record.SetStream(field, value)
|
||||
|
||||
Set *field* to the contents of the file named *value*, through
|
||||
:c:func:`MsiRecordSetStream`. *field* must be an integer; *value* a string.
|
||||
|
||||
|
||||
.. method:: Record.SetInteger(field, value)
|
||||
|
||||
Set *field* to *value* through :c:func:`MsiRecordSetInteger`. Both *field* and
|
||||
*value* must be an integer.
|
||||
|
||||
|
||||
.. method:: Record.ClearData()
|
||||
|
||||
Set all fields of the record to 0, through :c:func:`MsiRecordClearData`.
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
||||
`MsiRecordGetFieldCount <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370366.aspx>`_
|
||||
`MsiRecordSetString <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370373.aspx>`_
|
||||
`MsiRecordSetStream <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370372.aspx>`_
|
||||
`MsiRecordSetInteger <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370371.aspx>`_
|
||||
`MsiRecordClearData <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370364.aspx>`_
|
||||
|
||||
.. _msi-errors:
|
||||
|
||||
Errors
|
||||
------
|
||||
|
||||
All wrappers around MSI functions raise :exc:`MSIError`; the string inside the
|
||||
exception will contain more detail.
|
||||
|
||||
|
||||
.. _cab:
|
||||
|
||||
CAB Objects
|
||||
-----------
|
||||
|
||||
|
||||
.. class:: CAB(name)
|
||||
|
||||
The class :class:`CAB` represents a CAB file. During MSI construction, files
|
||||
will be added simultaneously to the ``Files`` table, and to a CAB file. Then,
|
||||
when all files have been added, the CAB file can be written, then added to the
|
||||
MSI file.
|
||||
|
||||
*name* is the name of the CAB file in the MSI file.
|
||||
|
||||
|
||||
.. method:: append(full, file, logical)
|
||||
|
||||
Add the file with the pathname *full* to the CAB file, under the name
|
||||
*logical*. If there is already a file named *logical*, a new file name is
|
||||
created.
|
||||
|
||||
Return the index of the file in the CAB file, and the new name of the file
|
||||
inside the CAB file.
|
||||
|
||||
|
||||
.. method:: commit(database)
|
||||
|
||||
Generate a CAB file, add it as a stream to the MSI file, put it into the
|
||||
``Media`` table, and remove the generated file from the disk.
|
||||
|
||||
|
||||
.. _msi-directory:
|
||||
|
||||
Directory Objects
|
||||
-----------------
|
||||
|
||||
|
||||
.. class:: Directory(database, cab, basedir, physical, logical, default, [componentflags])
|
||||
|
||||
Create a new directory in the Directory table. There is a current component at
|
||||
each point in time for the directory, which is either explicitly created through
|
||||
:meth:`start_component`, or implicitly when files are added for the first time.
|
||||
Files are added into the current component, and into the cab file. To create a
|
||||
directory, a base directory object needs to be specified (can be ``None``), the
|
||||
path to the physical directory, and a logical directory name. *default*
|
||||
specifies the DefaultDir slot in the directory table. *componentflags* specifies
|
||||
the default flags that new components get.
|
||||
|
||||
|
||||
.. method:: start_component(component=None, feature=None, flags=None, keyfile=None, uuid=None)
|
||||
|
||||
Add an entry to the Component table, and make this component the current
|
||||
component for this directory. If no component name is given, the directory
|
||||
name is used. If no *feature* is given, the current feature is used. If no
|
||||
*flags* are given, the directory's default flags are used. If no *keyfile*
|
||||
is given, the KeyPath is left null in the Component table.
|
||||
|
||||
|
||||
.. method:: add_file(file, src=None, version=None, language=None)
|
||||
|
||||
Add a file to the current component of the directory, starting a new one
|
||||
if there is no current component. By default, the file name in the source
|
||||
and the file table will be identical. If the *src* file is specified, it
|
||||
is interpreted relative to the current directory. Optionally, a *version*
|
||||
and a *language* can be specified for the entry in the File table.
|
||||
|
||||
|
||||
.. method:: glob(pattern, exclude=None)
|
||||
|
||||
Add a list of files to the current component as specified in the glob
|
||||
pattern. Individual files can be excluded in the *exclude* list.
|
||||
|
||||
|
||||
.. method:: remove_pyc()
|
||||
|
||||
Remove ``.pyc`` files on uninstall.
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
||||
`Directory Table <https://msdn.microsoft.com/en-us/library/windows/desktop/aa368295.aspx>`_
|
||||
`File Table <https://msdn.microsoft.com/en-us/library/windows/desktop/aa368596.aspx>`_
|
||||
`Component Table <https://msdn.microsoft.com/en-us/library/windows/desktop/aa368007.aspx>`_
|
||||
`FeatureComponents Table <https://msdn.microsoft.com/en-us/library/windows/desktop/aa368579.aspx>`_
|
||||
|
||||
.. _features:
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
|
||||
.. class:: Feature(db, id, title, desc, display, level=1, parent=None, directory=None, attributes=0)
|
||||
|
||||
Add a new record to the ``Feature`` table, using the values *id*, *parent.id*,
|
||||
*title*, *desc*, *display*, *level*, *directory*, and *attributes*. The
|
||||
resulting feature object can be passed to the :meth:`start_component` method of
|
||||
:class:`Directory`.
|
||||
|
||||
|
||||
.. method:: set_current()
|
||||
|
||||
Make this feature the current feature of :mod:`msilib`. New components are
|
||||
automatically added to the default feature, unless a feature is explicitly
|
||||
specified.
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
||||
`Feature Table <https://msdn.microsoft.com/en-us/library/windows/desktop/aa368585.aspx>`_
|
||||
|
||||
.. _msi-gui:
|
||||
|
||||
GUI classes
|
||||
-----------
|
||||
|
||||
:mod:`msilib` provides several classes that wrap the GUI tables in an MSI
|
||||
database. However, no standard user interface is provided.
|
||||
|
||||
|
||||
.. class:: Control(dlg, name)
|
||||
|
||||
Base class of the dialog controls. *dlg* is the dialog object the control
|
||||
belongs to, and *name* is the control's name.
|
||||
|
||||
|
||||
.. method:: event(event, argument, condition=1, ordering=None)
|
||||
|
||||
Make an entry into the ``ControlEvent`` table for this control.
|
||||
|
||||
|
||||
.. method:: mapping(event, attribute)
|
||||
|
||||
Make an entry into the ``EventMapping`` table for this control.
|
||||
|
||||
|
||||
.. method:: condition(action, condition)
|
||||
|
||||
Make an entry into the ``ControlCondition`` table for this control.
|
||||
|
||||
|
||||
.. class:: RadioButtonGroup(dlg, name, property)
|
||||
|
||||
Create a radio button control named *name*. *property* is the installer property
|
||||
that gets set when a radio button is selected.
|
||||
|
||||
|
||||
.. method:: add(name, x, y, width, height, text, value=None)
|
||||
|
||||
Add a radio button named *name* to the group, at the coordinates *x*, *y*,
|
||||
*width*, *height*, and with the label *text*. If *value* is ``None``, it
|
||||
defaults to *name*.
|
||||
|
||||
|
||||
.. class:: Dialog(db, name, x, y, w, h, attr, title, first, default, cancel)
|
||||
|
||||
Return a new :class:`Dialog` object. An entry in the ``Dialog`` table is made,
|
||||
with the specified coordinates, dialog attributes, title, name of the first,
|
||||
default, and cancel controls.
|
||||
|
||||
|
||||
.. method:: control(name, type, x, y, width, height, attributes, property, text, control_next, help)
|
||||
|
||||
Return a new :class:`Control` object. An entry in the ``Control`` table is
|
||||
made with the specified parameters.
|
||||
|
||||
This is a generic method; for specific types, specialized methods are
|
||||
provided.
|
||||
|
||||
|
||||
.. method:: text(name, x, y, width, height, attributes, text)
|
||||
|
||||
Add and return a ``Text`` control.
|
||||
|
||||
|
||||
.. method:: bitmap(name, x, y, width, height, text)
|
||||
|
||||
Add and return a ``Bitmap`` control.
|
||||
|
||||
|
||||
.. method:: line(name, x, y, width, height)
|
||||
|
||||
Add and return a ``Line`` control.
|
||||
|
||||
|
||||
.. method:: pushbutton(name, x, y, width, height, attributes, text, next_control)
|
||||
|
||||
Add and return a ``PushButton`` control.
|
||||
|
||||
|
||||
.. method:: radiogroup(name, x, y, width, height, attributes, property, text, next_control)
|
||||
|
||||
Add and return a ``RadioButtonGroup`` control.
|
||||
|
||||
|
||||
.. method:: checkbox(name, x, y, width, height, attributes, property, text, next_control)
|
||||
|
||||
Add and return a ``CheckBox`` control.
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
||||
`Dialog Table <https://msdn.microsoft.com/en-us/library/windows/desktop/aa368286.aspx>`_
|
||||
`Control Table <https://msdn.microsoft.com/en-us/library/windows/desktop/aa368044.aspx>`_
|
||||
`Control Types <https://msdn.microsoft.com/en-us/library/windows/desktop/aa368039.aspx>`_
|
||||
`ControlCondition Table <https://msdn.microsoft.com/en-us/library/windows/desktop/aa368035.aspx>`_
|
||||
`ControlEvent Table <https://msdn.microsoft.com/en-us/library/windows/desktop/aa368037.aspx>`_
|
||||
`EventMapping Table <https://msdn.microsoft.com/en-us/library/windows/desktop/aa368559.aspx>`_
|
||||
`RadioButton Table <https://msdn.microsoft.com/en-us/library/windows/desktop/aa370962.aspx>`_
|
||||
|
||||
.. _msi-tables:
|
||||
|
||||
Precomputed tables
|
||||
------------------
|
||||
|
||||
:mod:`msilib` provides a few subpackages that contain only schema and table
|
||||
definitions. Currently, these definitions are based on MSI version 2.0.
|
||||
|
||||
|
||||
.. data:: schema
|
||||
|
||||
This is the standard MSI schema for MSI 2.0, with the *tables* variable
|
||||
providing a list of table definitions, and *_Validation_records* providing the
|
||||
data for MSI validation.
|
||||
|
||||
|
||||
.. data:: sequence
|
||||
|
||||
This module contains table contents for the standard sequence tables:
|
||||
*AdminExecuteSequence*, *AdminUISequence*, *AdvtExecuteSequence*,
|
||||
*InstallExecuteSequence*, and *InstallUISequence*.
|
||||
|
||||
|
||||
.. data:: text
|
||||
|
||||
This module contains definitions for the UIText and ActionText tables, for the
|
||||
standard installer actions.
|
|
@ -15,6 +15,5 @@ backwards compatibility. They have been superseded by other modules.
|
|||
chunk.rst
|
||||
crypt.rst
|
||||
imghdr.rst
|
||||
msilib.rst
|
||||
optparse.rst
|
||||
uu.rst
|
||||
|
|
|
@ -161,7 +161,6 @@ Doc/library/logging.rst
|
|||
Doc/library/lzma.rst
|
||||
Doc/library/mailbox.rst
|
||||
Doc/library/mmap.rst
|
||||
Doc/library/msilib.rst
|
||||
Doc/library/msvcrt.rst
|
||||
Doc/library/multiprocessing.rst
|
||||
Doc/library/multiprocessing.shared_memory.rst
|
||||
|
|
|
@ -1422,7 +1422,7 @@ complete list of changes, or look through the SVN logs for all the details.
|
|||
(Contributed by Gregory K. Johnson. Funding was provided by Google's 2005
|
||||
Summer of Code.)
|
||||
|
||||
* New module: the :mod:`msilib` module allows creating Microsoft Installer
|
||||
* New module: the :mod:`!msilib` module allows creating Microsoft Installer
|
||||
:file:`.msi` files and CAB files. Some support for reading the :file:`.msi`
|
||||
database is also included. (Contributed by Martin von Löwis.)
|
||||
|
||||
|
|
|
@ -3135,7 +3135,7 @@ Port-Specific Changes: Windows
|
|||
registry reflection for 32-bit processes running on 64-bit systems.
|
||||
(:issue:`1753245`)
|
||||
|
||||
* The :mod:`msilib` module's :class:`Record` object
|
||||
* The :mod:`!msilib` module's :class:`Record` object
|
||||
gained :meth:`GetInteger` and :meth:`GetString` methods that
|
||||
return field values as an integer or a string.
|
||||
(Contributed by Floris Bruynooghe; :issue:`2125`.)
|
||||
|
|
|
@ -1731,7 +1731,7 @@ Modules
|
|||
slated for removal in Python 3.13:
|
||||
|
||||
+---------------------+---------------------+---------------------+---------------------+---------------------+
|
||||
| :mod:`aifc` | :mod:`chunk` | :mod:`msilib` | :mod:`!pipes` | :mod:`!telnetlib` |
|
||||
| :mod:`aifc` | :mod:`chunk` | :mod:`!msilib` | :mod:`!pipes` | :mod:`!telnetlib` |
|
||||
+---------------------+---------------------+---------------------+---------------------+---------------------+
|
||||
| :mod:`audioop` | :mod:`crypt` | :mod:`!nis` | :mod:`!sndhdr` | :mod:`uu` |
|
||||
+---------------------+---------------------+---------------------+---------------------+---------------------+
|
||||
|
|
|
@ -894,7 +894,7 @@ Modules (see :pep:`594`):
|
|||
* :mod:`crypt`
|
||||
* :mod:`imghdr`
|
||||
* :mod:`!mailcap`
|
||||
* :mod:`msilib`
|
||||
* :mod:`!msilib`
|
||||
* :mod:`!nis`
|
||||
* :mod:`!nntplib`
|
||||
* :mod:`!ossaudiodev`
|
||||
|
|
|
@ -198,6 +198,9 @@ Removed
|
|||
* :pep:`594`: Remove the :mod:`!xdrlib` module, deprecated in Python 3.11.
|
||||
(Contributed by Victor Stinner in :gh:`104773`.)
|
||||
|
||||
* :pep:`594`: Remove the :mod:`!msilib` module, deprecated in Python 3.11.
|
||||
(Contributed by Zachary Ware in :gh:`104773`.)
|
||||
|
||||
|
||||
Porting to Python 3.13
|
||||
======================
|
||||
|
|
|
@ -1133,7 +1133,7 @@ The MIME type of .bmp has been changed from ``'image/x-ms-bmp'`` to
|
|||
msilib
|
||||
------
|
||||
|
||||
The new :meth:`Database.Close() <msilib.Database.Close>` method can be used
|
||||
The new :meth:`!Database.Close()` method can be used
|
||||
to close the :abbr:`MSI` database.
|
||||
(Contributed by Berker Peksag in :issue:`20486`.)
|
||||
|
||||
|
|
|
@ -1,484 +0,0 @@
|
|||
# Copyright (C) 2005 Martin v. Löwis
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
from _msi import *
|
||||
import fnmatch
|
||||
import os
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
warnings._deprecated(__name__, remove=(3, 13))
|
||||
|
||||
AMD64 = "AMD64" in sys.version
|
||||
# Keep msilib.Win64 around to preserve backwards compatibility.
|
||||
Win64 = AMD64
|
||||
|
||||
# Partially taken from Wine
|
||||
datasizemask= 0x00ff
|
||||
type_valid= 0x0100
|
||||
type_localizable= 0x0200
|
||||
|
||||
typemask= 0x0c00
|
||||
type_long= 0x0000
|
||||
type_short= 0x0400
|
||||
type_string= 0x0c00
|
||||
type_binary= 0x0800
|
||||
|
||||
type_nullable= 0x1000
|
||||
type_key= 0x2000
|
||||
# XXX temporary, localizable?
|
||||
knownbits = datasizemask | type_valid | type_localizable | \
|
||||
typemask | type_nullable | type_key
|
||||
|
||||
class Table:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.fields = []
|
||||
|
||||
def add_field(self, index, name, type):
|
||||
self.fields.append((index,name,type))
|
||||
|
||||
def sql(self):
|
||||
fields = []
|
||||
keys = []
|
||||
self.fields.sort()
|
||||
fields = [None]*len(self.fields)
|
||||
for index, name, type in self.fields:
|
||||
index -= 1
|
||||
unk = type & ~knownbits
|
||||
if unk:
|
||||
print("%s.%s unknown bits %x" % (self.name, name, unk))
|
||||
size = type & datasizemask
|
||||
dtype = type & typemask
|
||||
if dtype == type_string:
|
||||
if size:
|
||||
tname="CHAR(%d)" % size
|
||||
else:
|
||||
tname="CHAR"
|
||||
elif dtype == type_short:
|
||||
assert size==2
|
||||
tname = "SHORT"
|
||||
elif dtype == type_long:
|
||||
assert size==4
|
||||
tname="LONG"
|
||||
elif dtype == type_binary:
|
||||
assert size==0
|
||||
tname="OBJECT"
|
||||
else:
|
||||
tname="unknown"
|
||||
print("%s.%sunknown integer type %d" % (self.name, name, size))
|
||||
if type & type_nullable:
|
||||
flags = ""
|
||||
else:
|
||||
flags = " NOT NULL"
|
||||
if type & type_localizable:
|
||||
flags += " LOCALIZABLE"
|
||||
fields[index] = "`%s` %s%s" % (name, tname, flags)
|
||||
if type & type_key:
|
||||
keys.append("`%s`" % name)
|
||||
fields = ", ".join(fields)
|
||||
keys = ", ".join(keys)
|
||||
return "CREATE TABLE %s (%s PRIMARY KEY %s)" % (self.name, fields, keys)
|
||||
|
||||
def create(self, db):
|
||||
v = db.OpenView(self.sql())
|
||||
v.Execute(None)
|
||||
v.Close()
|
||||
|
||||
class _Unspecified:pass
|
||||
def change_sequence(seq, action, seqno=_Unspecified, cond = _Unspecified):
|
||||
"Change the sequence number of an action in a sequence list"
|
||||
for i in range(len(seq)):
|
||||
if seq[i][0] == action:
|
||||
if cond is _Unspecified:
|
||||
cond = seq[i][1]
|
||||
if seqno is _Unspecified:
|
||||
seqno = seq[i][2]
|
||||
seq[i] = (action, cond, seqno)
|
||||
return
|
||||
raise ValueError("Action not found in sequence")
|
||||
|
||||
def add_data(db, table, values):
|
||||
v = db.OpenView("SELECT * FROM `%s`" % table)
|
||||
count = v.GetColumnInfo(MSICOLINFO_NAMES).GetFieldCount()
|
||||
r = CreateRecord(count)
|
||||
for value in values:
|
||||
assert len(value) == count, value
|
||||
for i in range(count):
|
||||
field = value[i]
|
||||
if isinstance(field, int):
|
||||
r.SetInteger(i+1,field)
|
||||
elif isinstance(field, str):
|
||||
r.SetString(i+1,field)
|
||||
elif field is None:
|
||||
pass
|
||||
elif isinstance(field, Binary):
|
||||
r.SetStream(i+1, field.name)
|
||||
else:
|
||||
raise TypeError("Unsupported type %s" % field.__class__.__name__)
|
||||
try:
|
||||
v.Modify(MSIMODIFY_INSERT, r)
|
||||
except Exception:
|
||||
raise MSIError("Could not insert "+repr(values)+" into "+table)
|
||||
|
||||
r.ClearData()
|
||||
v.Close()
|
||||
|
||||
|
||||
def add_stream(db, name, path):
|
||||
v = db.OpenView("INSERT INTO _Streams (Name, Data) VALUES ('%s', ?)" % name)
|
||||
r = CreateRecord(1)
|
||||
r.SetStream(1, path)
|
||||
v.Execute(r)
|
||||
v.Close()
|
||||
|
||||
def init_database(name, schema,
|
||||
ProductName, ProductCode, ProductVersion,
|
||||
Manufacturer):
|
||||
try:
|
||||
os.unlink(name)
|
||||
except OSError:
|
||||
pass
|
||||
ProductCode = ProductCode.upper()
|
||||
# Create the database
|
||||
db = OpenDatabase(name, MSIDBOPEN_CREATE)
|
||||
# Create the tables
|
||||
for t in schema.tables:
|
||||
t.create(db)
|
||||
# Fill the validation table
|
||||
add_data(db, "_Validation", schema._Validation_records)
|
||||
# Initialize the summary information, allowing atmost 20 properties
|
||||
si = db.GetSummaryInformation(20)
|
||||
si.SetProperty(PID_TITLE, "Installation Database")
|
||||
si.SetProperty(PID_SUBJECT, ProductName)
|
||||
si.SetProperty(PID_AUTHOR, Manufacturer)
|
||||
if AMD64:
|
||||
si.SetProperty(PID_TEMPLATE, "x64;1033")
|
||||
else:
|
||||
si.SetProperty(PID_TEMPLATE, "Intel;1033")
|
||||
si.SetProperty(PID_REVNUMBER, gen_uuid())
|
||||
si.SetProperty(PID_WORDCOUNT, 2) # long file names, compressed, original media
|
||||
si.SetProperty(PID_PAGECOUNT, 200)
|
||||
si.SetProperty(PID_APPNAME, "Python MSI Library")
|
||||
# XXX more properties
|
||||
si.Persist()
|
||||
add_data(db, "Property", [
|
||||
("ProductName", ProductName),
|
||||
("ProductCode", ProductCode),
|
||||
("ProductVersion", ProductVersion),
|
||||
("Manufacturer", Manufacturer),
|
||||
("ProductLanguage", "1033")])
|
||||
db.Commit()
|
||||
return db
|
||||
|
||||
def add_tables(db, module):
|
||||
for table in module.tables:
|
||||
add_data(db, table, getattr(module, table))
|
||||
|
||||
def make_id(str):
|
||||
identifier_chars = string.ascii_letters + string.digits + "._"
|
||||
str = "".join([c if c in identifier_chars else "_" for c in str])
|
||||
if str[0] in (string.digits + "."):
|
||||
str = "_" + str
|
||||
assert re.match("^[A-Za-z_][A-Za-z0-9_.]*$", str), "FILE"+str
|
||||
return str
|
||||
|
||||
def gen_uuid():
|
||||
return "{"+UuidCreate().upper()+"}"
|
||||
|
||||
class CAB:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.files = []
|
||||
self.filenames = set()
|
||||
self.index = 0
|
||||
|
||||
def gen_id(self, file):
|
||||
logical = _logical = make_id(file)
|
||||
pos = 1
|
||||
while logical in self.filenames:
|
||||
logical = "%s.%d" % (_logical, pos)
|
||||
pos += 1
|
||||
self.filenames.add(logical)
|
||||
return logical
|
||||
|
||||
def append(self, full, file, logical):
|
||||
if os.path.isdir(full):
|
||||
return
|
||||
if not logical:
|
||||
logical = self.gen_id(file)
|
||||
self.index += 1
|
||||
self.files.append((full, logical))
|
||||
return self.index, logical
|
||||
|
||||
def commit(self, db):
|
||||
from tempfile import mktemp
|
||||
filename = mktemp()
|
||||
FCICreate(filename, self.files)
|
||||
add_data(db, "Media",
|
||||
[(1, self.index, None, "#"+self.name, None, None)])
|
||||
add_stream(db, self.name, filename)
|
||||
os.unlink(filename)
|
||||
db.Commit()
|
||||
|
||||
_directories = set()
|
||||
class Directory:
|
||||
def __init__(self, db, cab, basedir, physical, _logical, default, componentflags=None):
|
||||
"""Create a new directory in the Directory table. There is a current component
|
||||
at each point in time for the directory, which is either explicitly created
|
||||
through start_component, or implicitly when files are added for the first
|
||||
time. Files are added into the current component, and into the cab file.
|
||||
To create a directory, a base directory object needs to be specified (can be
|
||||
None), the path to the physical directory, and a logical directory name.
|
||||
Default specifies the DefaultDir slot in the directory table. componentflags
|
||||
specifies the default flags that new components get."""
|
||||
index = 1
|
||||
_logical = make_id(_logical)
|
||||
logical = _logical
|
||||
while logical in _directories:
|
||||
logical = "%s%d" % (_logical, index)
|
||||
index += 1
|
||||
_directories.add(logical)
|
||||
self.db = db
|
||||
self.cab = cab
|
||||
self.basedir = basedir
|
||||
self.physical = physical
|
||||
self.logical = logical
|
||||
self.component = None
|
||||
self.short_names = set()
|
||||
self.ids = set()
|
||||
self.keyfiles = {}
|
||||
self.componentflags = componentflags
|
||||
if basedir:
|
||||
self.absolute = os.path.join(basedir.absolute, physical)
|
||||
blogical = basedir.logical
|
||||
else:
|
||||
self.absolute = physical
|
||||
blogical = None
|
||||
add_data(db, "Directory", [(logical, blogical, default)])
|
||||
|
||||
def start_component(self, component = None, feature = None, flags = None, keyfile = None, uuid=None):
|
||||
"""Add an entry to the Component table, and make this component the current for this
|
||||
directory. If no component name is given, the directory name is used. If no feature
|
||||
is given, the current feature is used. If no flags are given, the directory's default
|
||||
flags are used. If no keyfile is given, the KeyPath is left null in the Component
|
||||
table."""
|
||||
if flags is None:
|
||||
flags = self.componentflags
|
||||
if uuid is None:
|
||||
uuid = gen_uuid()
|
||||
else:
|
||||
uuid = uuid.upper()
|
||||
if component is None:
|
||||
component = self.logical
|
||||
self.component = component
|
||||
if AMD64:
|
||||
flags |= 256
|
||||
if keyfile:
|
||||
keyid = self.cab.gen_id(keyfile)
|
||||
self.keyfiles[keyfile] = keyid
|
||||
else:
|
||||
keyid = None
|
||||
add_data(self.db, "Component",
|
||||
[(component, uuid, self.logical, flags, None, keyid)])
|
||||
if feature is None:
|
||||
feature = current_feature
|
||||
add_data(self.db, "FeatureComponents",
|
||||
[(feature.id, component)])
|
||||
|
||||
def make_short(self, file):
|
||||
oldfile = file
|
||||
file = file.replace('+', '_')
|
||||
file = ''.join(c for c in file if not c in r' "/\[]:;=,')
|
||||
parts = file.split(".")
|
||||
if len(parts) > 1:
|
||||
prefix = "".join(parts[:-1]).upper()
|
||||
suffix = parts[-1].upper()
|
||||
if not prefix:
|
||||
prefix = suffix
|
||||
suffix = None
|
||||
else:
|
||||
prefix = file.upper()
|
||||
suffix = None
|
||||
if len(parts) < 3 and len(prefix) <= 8 and file == oldfile and (
|
||||
not suffix or len(suffix) <= 3):
|
||||
if suffix:
|
||||
file = prefix+"."+suffix
|
||||
else:
|
||||
file = prefix
|
||||
else:
|
||||
file = None
|
||||
if file is None or file in self.short_names:
|
||||
prefix = prefix[:6]
|
||||
if suffix:
|
||||
suffix = suffix[:3]
|
||||
pos = 1
|
||||
while 1:
|
||||
if suffix:
|
||||
file = "%s~%d.%s" % (prefix, pos, suffix)
|
||||
else:
|
||||
file = "%s~%d" % (prefix, pos)
|
||||
if file not in self.short_names: break
|
||||
pos += 1
|
||||
assert pos < 10000
|
||||
if pos in (10, 100, 1000):
|
||||
prefix = prefix[:-1]
|
||||
self.short_names.add(file)
|
||||
assert not re.search(r'[\?|><:/*"+,;=\[\]]', file) # restrictions on short names
|
||||
return file
|
||||
|
||||
def add_file(self, file, src=None, version=None, language=None):
|
||||
"""Add a file to the current component of the directory, starting a new one
|
||||
if there is no current component. By default, the file name in the source
|
||||
and the file table will be identical. If the src file is specified, it is
|
||||
interpreted relative to the current directory. Optionally, a version and a
|
||||
language can be specified for the entry in the File table."""
|
||||
if not self.component:
|
||||
self.start_component(self.logical, current_feature, 0)
|
||||
if not src:
|
||||
# Allow relative paths for file if src is not specified
|
||||
src = file
|
||||
file = os.path.basename(file)
|
||||
absolute = os.path.join(self.absolute, src)
|
||||
assert not re.search(r'[\?|><:/*]"', file) # restrictions on long names
|
||||
if file in self.keyfiles:
|
||||
logical = self.keyfiles[file]
|
||||
else:
|
||||
logical = None
|
||||
sequence, logical = self.cab.append(absolute, file, logical)
|
||||
assert logical not in self.ids
|
||||
self.ids.add(logical)
|
||||
short = self.make_short(file)
|
||||
full = "%s|%s" % (short, file)
|
||||
filesize = os.stat(absolute).st_size
|
||||
# constants.msidbFileAttributesVital
|
||||
# Compressed omitted, since it is the database default
|
||||
# could add r/o, system, hidden
|
||||
attributes = 512
|
||||
add_data(self.db, "File",
|
||||
[(logical, self.component, full, filesize, version,
|
||||
language, attributes, sequence)])
|
||||
#if not version:
|
||||
# # Add hash if the file is not versioned
|
||||
# filehash = FileHash(absolute, 0)
|
||||
# add_data(self.db, "MsiFileHash",
|
||||
# [(logical, 0, filehash.IntegerData(1),
|
||||
# filehash.IntegerData(2), filehash.IntegerData(3),
|
||||
# filehash.IntegerData(4))])
|
||||
# Automatically remove .pyc files on uninstall (2)
|
||||
# XXX: adding so many RemoveFile entries makes installer unbelievably
|
||||
# slow. So instead, we have to use wildcard remove entries
|
||||
if file.endswith(".py"):
|
||||
add_data(self.db, "RemoveFile",
|
||||
[(logical+"c", self.component, "%sC|%sc" % (short, file),
|
||||
self.logical, 2),
|
||||
(logical+"o", self.component, "%sO|%so" % (short, file),
|
||||
self.logical, 2)])
|
||||
return logical
|
||||
|
||||
def glob(self, pattern, exclude = None):
|
||||
"""Add a list of files to the current component as specified in the
|
||||
glob pattern. Individual files can be excluded in the exclude list."""
|
||||
try:
|
||||
files = os.listdir(self.absolute)
|
||||
except OSError:
|
||||
return []
|
||||
if pattern[:1] != '.':
|
||||
files = (f for f in files if f[0] != '.')
|
||||
files = fnmatch.filter(files, pattern)
|
||||
for f in files:
|
||||
if exclude and f in exclude: continue
|
||||
self.add_file(f)
|
||||
return files
|
||||
|
||||
def remove_pyc(self):
|
||||
"Remove .pyc files on uninstall"
|
||||
add_data(self.db, "RemoveFile",
|
||||
[(self.component+"c", self.component, "*.pyc", self.logical, 2)])
|
||||
|
||||
class Binary:
|
||||
def __init__(self, fname):
|
||||
self.name = fname
|
||||
def __repr__(self):
|
||||
return 'msilib.Binary(os.path.join(dirname,"%s"))' % self.name
|
||||
|
||||
class Feature:
|
||||
def __init__(self, db, id, title, desc, display, level = 1,
|
||||
parent=None, directory = None, attributes=0):
|
||||
self.id = id
|
||||
if parent:
|
||||
parent = parent.id
|
||||
add_data(db, "Feature",
|
||||
[(id, parent, title, desc, display,
|
||||
level, directory, attributes)])
|
||||
def set_current(self):
|
||||
global current_feature
|
||||
current_feature = self
|
||||
|
||||
class Control:
|
||||
def __init__(self, dlg, name):
|
||||
self.dlg = dlg
|
||||
self.name = name
|
||||
|
||||
def event(self, event, argument, condition = "1", ordering = None):
|
||||
add_data(self.dlg.db, "ControlEvent",
|
||||
[(self.dlg.name, self.name, event, argument,
|
||||
condition, ordering)])
|
||||
|
||||
def mapping(self, event, attribute):
|
||||
add_data(self.dlg.db, "EventMapping",
|
||||
[(self.dlg.name, self.name, event, attribute)])
|
||||
|
||||
def condition(self, action, condition):
|
||||
add_data(self.dlg.db, "ControlCondition",
|
||||
[(self.dlg.name, self.name, action, condition)])
|
||||
|
||||
class RadioButtonGroup(Control):
|
||||
def __init__(self, dlg, name, property):
|
||||
self.dlg = dlg
|
||||
self.name = name
|
||||
self.property = property
|
||||
self.index = 1
|
||||
|
||||
def add(self, name, x, y, w, h, text, value = None):
|
||||
if value is None:
|
||||
value = name
|
||||
add_data(self.dlg.db, "RadioButton",
|
||||
[(self.property, self.index, value,
|
||||
x, y, w, h, text, None)])
|
||||
self.index += 1
|
||||
|
||||
class Dialog:
|
||||
def __init__(self, db, name, x, y, w, h, attr, title, first, default, cancel):
|
||||
self.db = db
|
||||
self.name = name
|
||||
self.x, self.y, self.w, self.h = x,y,w,h
|
||||
add_data(db, "Dialog", [(name, x,y,w,h,attr,title,first,default,cancel)])
|
||||
|
||||
def control(self, name, type, x, y, w, h, attr, prop, text, next, help):
|
||||
add_data(self.db, "Control",
|
||||
[(self.name, name, type, x, y, w, h, attr, prop, text, next, help)])
|
||||
return Control(self, name)
|
||||
|
||||
def text(self, name, x, y, w, h, attr, text):
|
||||
return self.control(name, "Text", x, y, w, h, attr, None,
|
||||
text, None, None)
|
||||
|
||||
def bitmap(self, name, x, y, w, h, text):
|
||||
return self.control(name, "Bitmap", x, y, w, h, 1, None, text, None, None)
|
||||
|
||||
def line(self, name, x, y, w, h):
|
||||
return self.control(name, "Line", x, y, w, h, 1, None, None, None, None)
|
||||
|
||||
def pushbutton(self, name, x, y, w, h, attr, text, next):
|
||||
return self.control(name, "PushButton", x, y, w, h, attr, None, text, next, None)
|
||||
|
||||
def radiogroup(self, name, x, y, w, h, attr, prop, text, next):
|
||||
add_data(self.db, "Control",
|
||||
[(self.name, name, "RadioButtonGroup",
|
||||
x, y, w, h, attr, prop, text, next, None)])
|
||||
return RadioButtonGroup(self, name, prop)
|
||||
|
||||
def checkbox(self, name, x, y, w, h, attr, prop, text, next):
|
||||
return self.control(name, "CheckBox", x, y, w, h, attr, prop, text, next, None)
|
1007
Lib/msilib/schema.py
1007
Lib/msilib/schema.py
File diff suppressed because it is too large
Load Diff
|
@ -1,126 +0,0 @@
|
|||
AdminExecuteSequence = [
|
||||
('InstallInitialize', None, 1500),
|
||||
('InstallFinalize', None, 6600),
|
||||
('InstallFiles', None, 4000),
|
||||
('InstallAdminPackage', None, 3900),
|
||||
('FileCost', None, 900),
|
||||
('CostInitialize', None, 800),
|
||||
('CostFinalize', None, 1000),
|
||||
('InstallValidate', None, 1400),
|
||||
]
|
||||
|
||||
AdminUISequence = [
|
||||
('FileCost', None, 900),
|
||||
('CostInitialize', None, 800),
|
||||
('CostFinalize', None, 1000),
|
||||
('ExecuteAction', None, 1300),
|
||||
('ExitDialog', None, -1),
|
||||
('FatalError', None, -3),
|
||||
('UserExit', None, -2),
|
||||
]
|
||||
|
||||
AdvtExecuteSequence = [
|
||||
('InstallInitialize', None, 1500),
|
||||
('InstallFinalize', None, 6600),
|
||||
('CostInitialize', None, 800),
|
||||
('CostFinalize', None, 1000),
|
||||
('InstallValidate', None, 1400),
|
||||
('CreateShortcuts', None, 4500),
|
||||
('MsiPublishAssemblies', None, 6250),
|
||||
('PublishComponents', None, 6200),
|
||||
('PublishFeatures', None, 6300),
|
||||
('PublishProduct', None, 6400),
|
||||
('RegisterClassInfo', None, 4600),
|
||||
('RegisterExtensionInfo', None, 4700),
|
||||
('RegisterMIMEInfo', None, 4900),
|
||||
('RegisterProgIdInfo', None, 4800),
|
||||
]
|
||||
|
||||
InstallExecuteSequence = [
|
||||
('InstallInitialize', None, 1500),
|
||||
('InstallFinalize', None, 6600),
|
||||
('InstallFiles', None, 4000),
|
||||
('FileCost', None, 900),
|
||||
('CostInitialize', None, 800),
|
||||
('CostFinalize', None, 1000),
|
||||
('InstallValidate', None, 1400),
|
||||
('CreateShortcuts', None, 4500),
|
||||
('MsiPublishAssemblies', None, 6250),
|
||||
('PublishComponents', None, 6200),
|
||||
('PublishFeatures', None, 6300),
|
||||
('PublishProduct', None, 6400),
|
||||
('RegisterClassInfo', None, 4600),
|
||||
('RegisterExtensionInfo', None, 4700),
|
||||
('RegisterMIMEInfo', None, 4900),
|
||||
('RegisterProgIdInfo', None, 4800),
|
||||
('AllocateRegistrySpace', 'NOT Installed', 1550),
|
||||
('AppSearch', None, 400),
|
||||
('BindImage', None, 4300),
|
||||
('CCPSearch', 'NOT Installed', 500),
|
||||
('CreateFolders', None, 3700),
|
||||
('DeleteServices', 'VersionNT', 2000),
|
||||
('DuplicateFiles', None, 4210),
|
||||
('FindRelatedProducts', None, 200),
|
||||
('InstallODBC', None, 5400),
|
||||
('InstallServices', 'VersionNT', 5800),
|
||||
('IsolateComponents', None, 950),
|
||||
('LaunchConditions', None, 100),
|
||||
('MigrateFeatureStates', None, 1200),
|
||||
('MoveFiles', None, 3800),
|
||||
('PatchFiles', None, 4090),
|
||||
('ProcessComponents', None, 1600),
|
||||
('RegisterComPlus', None, 5700),
|
||||
('RegisterFonts', None, 5300),
|
||||
('RegisterProduct', None, 6100),
|
||||
('RegisterTypeLibraries', None, 5500),
|
||||
('RegisterUser', None, 6000),
|
||||
('RemoveDuplicateFiles', None, 3400),
|
||||
('RemoveEnvironmentStrings', None, 3300),
|
||||
('RemoveExistingProducts', None, 6700),
|
||||
('RemoveFiles', None, 3500),
|
||||
('RemoveFolders', None, 3600),
|
||||
('RemoveIniValues', None, 3100),
|
||||
('RemoveODBC', None, 2400),
|
||||
('RemoveRegistryValues', None, 2600),
|
||||
('RemoveShortcuts', None, 3200),
|
||||
('RMCCPSearch', 'NOT Installed', 600),
|
||||
('SelfRegModules', None, 5600),
|
||||
('SelfUnregModules', None, 2200),
|
||||
('SetODBCFolders', None, 1100),
|
||||
('StartServices', 'VersionNT', 5900),
|
||||
('StopServices', 'VersionNT', 1900),
|
||||
('MsiUnpublishAssemblies', None, 1750),
|
||||
('UnpublishComponents', None, 1700),
|
||||
('UnpublishFeatures', None, 1800),
|
||||
('UnregisterClassInfo', None, 2700),
|
||||
('UnregisterComPlus', None, 2100),
|
||||
('UnregisterExtensionInfo', None, 2800),
|
||||
('UnregisterFonts', None, 2500),
|
||||
('UnregisterMIMEInfo', None, 3000),
|
||||
('UnregisterProgIdInfo', None, 2900),
|
||||
('UnregisterTypeLibraries', None, 2300),
|
||||
('ValidateProductID', None, 700),
|
||||
('WriteEnvironmentStrings', None, 5200),
|
||||
('WriteIniValues', None, 5100),
|
||||
('WriteRegistryValues', None, 5000),
|
||||
]
|
||||
|
||||
InstallUISequence = [
|
||||
('FileCost', None, 900),
|
||||
('CostInitialize', None, 800),
|
||||
('CostFinalize', None, 1000),
|
||||
('ExecuteAction', None, 1300),
|
||||
('ExitDialog', None, -1),
|
||||
('FatalError', None, -3),
|
||||
('UserExit', None, -2),
|
||||
('AppSearch', None, 400),
|
||||
('CCPSearch', 'NOT Installed', 500),
|
||||
('FindRelatedProducts', None, 200),
|
||||
('IsolateComponents', None, 950),
|
||||
('LaunchConditions', None, 100),
|
||||
('MigrateFeatureStates', None, 1200),
|
||||
('RMCCPSearch', 'NOT Installed', 600),
|
||||
('ValidateProductID', None, 700),
|
||||
]
|
||||
|
||||
tables=['AdminExecuteSequence', 'AdminUISequence', 'AdvtExecuteSequence', 'InstallExecuteSequence', 'InstallUISequence']
|
|
@ -1,129 +0,0 @@
|
|||
import msilib,os;dirname=os.path.dirname(__file__)
|
||||
|
||||
ActionText = [
|
||||
('InstallValidate', 'Validating install', None),
|
||||
('InstallFiles', 'Copying new files', 'File: [1], Directory: [9], Size: [6]'),
|
||||
('InstallAdminPackage', 'Copying network install files', 'File: [1], Directory: [9], Size: [6]'),
|
||||
('FileCost', 'Computing space requirements', None),
|
||||
('CostInitialize', 'Computing space requirements', None),
|
||||
('CostFinalize', 'Computing space requirements', None),
|
||||
('CreateShortcuts', 'Creating shortcuts', 'Shortcut: [1]'),
|
||||
('PublishComponents', 'Publishing Qualified Components', 'Component ID: [1], Qualifier: [2]'),
|
||||
('PublishFeatures', 'Publishing Product Features', 'Feature: [1]'),
|
||||
('PublishProduct', 'Publishing product information', None),
|
||||
('RegisterClassInfo', 'Registering Class servers', 'Class Id: [1]'),
|
||||
('RegisterExtensionInfo', 'Registering extension servers', 'Extension: [1]'),
|
||||
('RegisterMIMEInfo', 'Registering MIME info', 'MIME Content Type: [1], Extension: [2]'),
|
||||
('RegisterProgIdInfo', 'Registering program identifiers', 'ProgId: [1]'),
|
||||
('AllocateRegistrySpace', 'Allocating registry space', 'Free space: [1]'),
|
||||
('AppSearch', 'Searching for installed applications', 'Property: [1], Signature: [2]'),
|
||||
('BindImage', 'Binding executables', 'File: [1]'),
|
||||
('CCPSearch', 'Searching for qualifying products', None),
|
||||
('CreateFolders', 'Creating folders', 'Folder: [1]'),
|
||||
('DeleteServices', 'Deleting services', 'Service: [1]'),
|
||||
('DuplicateFiles', 'Creating duplicate files', 'File: [1], Directory: [9], Size: [6]'),
|
||||
('FindRelatedProducts', 'Searching for related applications', 'Found application: [1]'),
|
||||
('InstallODBC', 'Installing ODBC components', None),
|
||||
('InstallServices', 'Installing new services', 'Service: [2]'),
|
||||
('LaunchConditions', 'Evaluating launch conditions', None),
|
||||
('MigrateFeatureStates', 'Migrating feature states from related applications', 'Application: [1]'),
|
||||
('MoveFiles', 'Moving files', 'File: [1], Directory: [9], Size: [6]'),
|
||||
('PatchFiles', 'Patching files', 'File: [1], Directory: [2], Size: [3]'),
|
||||
('ProcessComponents', 'Updating component registration', None),
|
||||
('RegisterComPlus', 'Registering COM+ Applications and Components', 'AppId: [1]{{, AppType: [2], Users: [3], RSN: [4]}}'),
|
||||
('RegisterFonts', 'Registering fonts', 'Font: [1]'),
|
||||
('RegisterProduct', 'Registering product', '[1]'),
|
||||
('RegisterTypeLibraries', 'Registering type libraries', 'LibID: [1]'),
|
||||
('RegisterUser', 'Registering user', '[1]'),
|
||||
('RemoveDuplicateFiles', 'Removing duplicated files', 'File: [1], Directory: [9]'),
|
||||
('RemoveEnvironmentStrings', 'Updating environment strings', 'Name: [1], Value: [2], Action [3]'),
|
||||
('RemoveExistingProducts', 'Removing applications', 'Application: [1], Command line: [2]'),
|
||||
('RemoveFiles', 'Removing files', 'File: [1], Directory: [9]'),
|
||||
('RemoveFolders', 'Removing folders', 'Folder: [1]'),
|
||||
('RemoveIniValues', 'Removing INI files entries', 'File: [1], Section: [2], Key: [3], Value: [4]'),
|
||||
('RemoveODBC', 'Removing ODBC components', None),
|
||||
('RemoveRegistryValues', 'Removing system registry values', 'Key: [1], Name: [2]'),
|
||||
('RemoveShortcuts', 'Removing shortcuts', 'Shortcut: [1]'),
|
||||
('RMCCPSearch', 'Searching for qualifying products', None),
|
||||
('SelfRegModules', 'Registering modules', 'File: [1], Folder: [2]'),
|
||||
('SelfUnregModules', 'Unregistering modules', 'File: [1], Folder: [2]'),
|
||||
('SetODBCFolders', 'Initializing ODBC directories', None),
|
||||
('StartServices', 'Starting services', 'Service: [1]'),
|
||||
('StopServices', 'Stopping services', 'Service: [1]'),
|
||||
('UnpublishComponents', 'Unpublishing Qualified Components', 'Component ID: [1], Qualifier: [2]'),
|
||||
('UnpublishFeatures', 'Unpublishing Product Features', 'Feature: [1]'),
|
||||
('UnregisterClassInfo', 'Unregister Class servers', 'Class Id: [1]'),
|
||||
('UnregisterComPlus', 'Unregistering COM+ Applications and Components', 'AppId: [1]{{, AppType: [2]}}'),
|
||||
('UnregisterExtensionInfo', 'Unregistering extension servers', 'Extension: [1]'),
|
||||
('UnregisterFonts', 'Unregistering fonts', 'Font: [1]'),
|
||||
('UnregisterMIMEInfo', 'Unregistering MIME info', 'MIME Content Type: [1], Extension: [2]'),
|
||||
('UnregisterProgIdInfo', 'Unregistering program identifiers', 'ProgId: [1]'),
|
||||
('UnregisterTypeLibraries', 'Unregistering type libraries', 'LibID: [1]'),
|
||||
('WriteEnvironmentStrings', 'Updating environment strings', 'Name: [1], Value: [2], Action [3]'),
|
||||
('WriteIniValues', 'Writing INI files values', 'File: [1], Section: [2], Key: [3], Value: [4]'),
|
||||
('WriteRegistryValues', 'Writing system registry values', 'Key: [1], Name: [2], Value: [3]'),
|
||||
('Advertise', 'Advertising application', None),
|
||||
('GenerateScript', 'Generating script operations for action:', '[1]'),
|
||||
('InstallSFPCatalogFile', 'Installing system catalog', 'File: [1], Dependencies: [2]'),
|
||||
('MsiPublishAssemblies', 'Publishing assembly information', 'Application Context:[1], Assembly Name:[2]'),
|
||||
('MsiUnpublishAssemblies', 'Unpublishing assembly information', 'Application Context:[1], Assembly Name:[2]'),
|
||||
('Rollback', 'Rolling back action:', '[1]'),
|
||||
('RollbackCleanup', 'Removing backup files', 'File: [1]'),
|
||||
('UnmoveFiles', 'Removing moved files', 'File: [1], Directory: [9]'),
|
||||
('UnpublishProduct', 'Unpublishing product information', None),
|
||||
]
|
||||
|
||||
UIText = [
|
||||
('AbsentPath', None),
|
||||
('bytes', 'bytes'),
|
||||
('GB', 'GB'),
|
||||
('KB', 'KB'),
|
||||
('MB', 'MB'),
|
||||
('MenuAbsent', 'Entire feature will be unavailable'),
|
||||
('MenuAdvertise', 'Feature will be installed when required'),
|
||||
('MenuAllCD', 'Entire feature will be installed to run from CD'),
|
||||
('MenuAllLocal', 'Entire feature will be installed on local hard drive'),
|
||||
('MenuAllNetwork', 'Entire feature will be installed to run from network'),
|
||||
('MenuCD', 'Will be installed to run from CD'),
|
||||
('MenuLocal', 'Will be installed on local hard drive'),
|
||||
('MenuNetwork', 'Will be installed to run from network'),
|
||||
('ScriptInProgress', 'Gathering required information...'),
|
||||
('SelAbsentAbsent', 'This feature will remain uninstalled'),
|
||||
('SelAbsentAdvertise', 'This feature will be set to be installed when required'),
|
||||
('SelAbsentCD', 'This feature will be installed to run from CD'),
|
||||
('SelAbsentLocal', 'This feature will be installed on the local hard drive'),
|
||||
('SelAbsentNetwork', 'This feature will be installed to run from the network'),
|
||||
('SelAdvertiseAbsent', 'This feature will become unavailable'),
|
||||
('SelAdvertiseAdvertise', 'Will be installed when required'),
|
||||
('SelAdvertiseCD', 'This feature will be available to run from CD'),
|
||||
('SelAdvertiseLocal', 'This feature will be installed on your local hard drive'),
|
||||
('SelAdvertiseNetwork', 'This feature will be available to run from the network'),
|
||||
('SelCDAbsent', "This feature will be uninstalled completely, you won't be able to run it from CD"),
|
||||
('SelCDAdvertise', 'This feature will change from run from CD state to set to be installed when required'),
|
||||
('SelCDCD', 'This feature will remain to be run from CD'),
|
||||
('SelCDLocal', 'This feature will change from run from CD state to be installed on the local hard drive'),
|
||||
('SelChildCostNeg', 'This feature frees up [1] on your hard drive.'),
|
||||
('SelChildCostPos', 'This feature requires [1] on your hard drive.'),
|
||||
('SelCostPending', 'Compiling cost for this feature...'),
|
||||
('SelLocalAbsent', 'This feature will be completely removed'),
|
||||
('SelLocalAdvertise', 'This feature will be removed from your local hard drive, but will be set to be installed when required'),
|
||||
('SelLocalCD', 'This feature will be removed from your local hard drive, but will be still available to run from CD'),
|
||||
('SelLocalLocal', 'This feature will remain on you local hard drive'),
|
||||
('SelLocalNetwork', 'This feature will be removed from your local hard drive, but will be still available to run from the network'),
|
||||
('SelNetworkAbsent', "This feature will be uninstalled completely, you won't be able to run it from the network"),
|
||||
('SelNetworkAdvertise', 'This feature will change from run from network state to set to be installed when required'),
|
||||
('SelNetworkLocal', 'This feature will change from run from network state to be installed on the local hard drive'),
|
||||
('SelNetworkNetwork', 'This feature will remain to be run from the network'),
|
||||
('SelParentCostNegNeg', 'This feature frees up [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures free up [4] on your hard drive.'),
|
||||
('SelParentCostNegPos', 'This feature frees up [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures require [4] on your hard drive.'),
|
||||
('SelParentCostPosNeg', 'This feature requires [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures free up [4] on your hard drive.'),
|
||||
('SelParentCostPosPos', 'This feature requires [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures require [4] on your hard drive.'),
|
||||
('TimeRemaining', 'Time remaining: {[1] minutes }{[2] seconds}'),
|
||||
('VolumeCostAvailable', 'Available'),
|
||||
('VolumeCostDifference', 'Difference'),
|
||||
('VolumeCostRequired', 'Required'),
|
||||
('VolumeCostSize', 'Disk Size'),
|
||||
('VolumeCostVolume', 'Volume'),
|
||||
]
|
||||
|
||||
tables=['ActionText', 'UIText']
|
|
@ -1,166 +0,0 @@
|
|||
""" Test suite for the code in msilib """
|
||||
import os
|
||||
import unittest
|
||||
from test.support.import_helper import import_module
|
||||
from test.support.os_helper import TESTFN, unlink
|
||||
import warnings
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore", DeprecationWarning)
|
||||
msilib = import_module('msilib')
|
||||
import msilib.schema
|
||||
|
||||
|
||||
def init_database():
|
||||
path = TESTFN + '.msi'
|
||||
db = msilib.init_database(
|
||||
path,
|
||||
msilib.schema,
|
||||
'Python Tests',
|
||||
'product_code',
|
||||
'1.0',
|
||||
'PSF',
|
||||
)
|
||||
return db, path
|
||||
|
||||
|
||||
class MsiDatabaseTestCase(unittest.TestCase):
|
||||
|
||||
def test_view_fetch_returns_none(self):
|
||||
db, db_path = init_database()
|
||||
properties = []
|
||||
view = db.OpenView('SELECT Property, Value FROM Property')
|
||||
view.Execute(None)
|
||||
while True:
|
||||
record = view.Fetch()
|
||||
if record is None:
|
||||
break
|
||||
properties.append(record.GetString(1))
|
||||
view.Close()
|
||||
db.Close()
|
||||
self.assertEqual(
|
||||
properties,
|
||||
[
|
||||
'ProductName', 'ProductCode', 'ProductVersion',
|
||||
'Manufacturer', 'ProductLanguage',
|
||||
]
|
||||
)
|
||||
self.addCleanup(unlink, db_path)
|
||||
|
||||
def test_view_non_ascii(self):
|
||||
db, db_path = init_database()
|
||||
view = db.OpenView("SELECT 'ß-розпад' FROM Property")
|
||||
view.Execute(None)
|
||||
record = view.Fetch()
|
||||
self.assertEqual(record.GetString(1), 'ß-розпад')
|
||||
view.Close()
|
||||
db.Close()
|
||||
self.addCleanup(unlink, db_path)
|
||||
|
||||
def test_summaryinfo_getproperty_issue1104(self):
|
||||
db, db_path = init_database()
|
||||
try:
|
||||
sum_info = db.GetSummaryInformation(99)
|
||||
title = sum_info.GetProperty(msilib.PID_TITLE)
|
||||
self.assertEqual(title, b"Installation Database")
|
||||
|
||||
sum_info.SetProperty(msilib.PID_TITLE, "a" * 999)
|
||||
title = sum_info.GetProperty(msilib.PID_TITLE)
|
||||
self.assertEqual(title, b"a" * 999)
|
||||
|
||||
sum_info.SetProperty(msilib.PID_TITLE, "a" * 1000)
|
||||
title = sum_info.GetProperty(msilib.PID_TITLE)
|
||||
self.assertEqual(title, b"a" * 1000)
|
||||
|
||||
sum_info.SetProperty(msilib.PID_TITLE, "a" * 1001)
|
||||
title = sum_info.GetProperty(msilib.PID_TITLE)
|
||||
self.assertEqual(title, b"a" * 1001)
|
||||
finally:
|
||||
db = None
|
||||
sum_info = None
|
||||
os.unlink(db_path)
|
||||
|
||||
def test_database_open_failed(self):
|
||||
with self.assertRaises(msilib.MSIError) as cm:
|
||||
msilib.OpenDatabase('non-existent.msi', msilib.MSIDBOPEN_READONLY)
|
||||
self.assertEqual(str(cm.exception), 'open failed')
|
||||
|
||||
def test_database_create_failed(self):
|
||||
db_path = os.path.join(TESTFN, 'test.msi')
|
||||
with self.assertRaises(msilib.MSIError) as cm:
|
||||
msilib.OpenDatabase(db_path, msilib.MSIDBOPEN_CREATE)
|
||||
self.assertEqual(str(cm.exception), 'create failed')
|
||||
|
||||
def test_get_property_vt_empty(self):
|
||||
db, db_path = init_database()
|
||||
summary = db.GetSummaryInformation(0)
|
||||
self.assertIsNone(summary.GetProperty(msilib.PID_SECURITY))
|
||||
db.Close()
|
||||
self.addCleanup(unlink, db_path)
|
||||
|
||||
def test_directory_start_component_keyfile(self):
|
||||
db, db_path = init_database()
|
||||
self.addCleanup(unlink, db_path)
|
||||
self.addCleanup(db.Close)
|
||||
self.addCleanup(msilib._directories.clear)
|
||||
feature = msilib.Feature(db, 0, 'Feature', 'A feature', 'Python')
|
||||
cab = msilib.CAB('CAB')
|
||||
dir = msilib.Directory(db, cab, None, TESTFN, 'TARGETDIR',
|
||||
'SourceDir', 0)
|
||||
dir.start_component(None, feature, None, 'keyfile')
|
||||
|
||||
def test_getproperty_uninitialized_var(self):
|
||||
db, db_path = init_database()
|
||||
self.addCleanup(unlink, db_path)
|
||||
self.addCleanup(db.Close)
|
||||
si = db.GetSummaryInformation(0)
|
||||
with self.assertRaises(msilib.MSIError):
|
||||
si.GetProperty(-1)
|
||||
|
||||
def test_FCICreate(self):
|
||||
filepath = TESTFN + '.txt'
|
||||
cabpath = TESTFN + '.cab'
|
||||
self.addCleanup(unlink, filepath)
|
||||
with open(filepath, 'wb'):
|
||||
pass
|
||||
self.addCleanup(unlink, cabpath)
|
||||
msilib.FCICreate(cabpath, [(filepath, 'test.txt')])
|
||||
self.assertTrue(os.path.isfile(cabpath))
|
||||
|
||||
|
||||
class Test_make_id(unittest.TestCase):
|
||||
#http://msdn.microsoft.com/en-us/library/aa369212(v=vs.85).aspx
|
||||
"""The Identifier data type is a text string. Identifiers may contain the
|
||||
ASCII characters A-Z (a-z), digits, underscores (_), or periods (.).
|
||||
However, every identifier must begin with either a letter or an
|
||||
underscore.
|
||||
"""
|
||||
|
||||
def test_is_no_change_required(self):
|
||||
self.assertEqual(
|
||||
msilib.make_id("short"), "short")
|
||||
self.assertEqual(
|
||||
msilib.make_id("nochangerequired"), "nochangerequired")
|
||||
self.assertEqual(
|
||||
msilib.make_id("one.dot"), "one.dot")
|
||||
self.assertEqual(
|
||||
msilib.make_id("_"), "_")
|
||||
self.assertEqual(
|
||||
msilib.make_id("a"), "a")
|
||||
#self.assertEqual(
|
||||
# msilib.make_id(""), "")
|
||||
|
||||
def test_invalid_first_char(self):
|
||||
self.assertEqual(
|
||||
msilib.make_id("9.short"), "_9.short")
|
||||
self.assertEqual(
|
||||
msilib.make_id(".short"), "_.short")
|
||||
|
||||
def test_invalid_any_char(self):
|
||||
self.assertEqual(
|
||||
msilib.make_id(".s\x82ort"), "_.s_ort")
|
||||
self.assertEqual(
|
||||
msilib.make_id(".s\x82o?*+rt"), "_.s_o___rt")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
|
@ -2986,7 +2986,7 @@ Update Windows release to include SQLite 3.32.3.
|
|||
.. nonce: jpZzzh
|
||||
.. section: Windows
|
||||
|
||||
:mod:`msilib` now supports creating CAB files with non-ASCII file path and
|
||||
:mod:`!msilib` now supports creating CAB files with non-ASCII file path and
|
||||
adding files with non-ASCII file path to them.
|
||||
|
||||
..
|
||||
|
@ -2996,9 +2996,9 @@ adding files with non-ASCII file path to them.
|
|||
.. nonce: gaQc3C
|
||||
.. section: Windows
|
||||
|
||||
Fixed support of non-ASCII names in functions :func:`msilib.OpenDatabase`
|
||||
and :func:`msilib.init_database` and non-ASCII SQL in method
|
||||
:meth:`msilib.Database.OpenView`.
|
||||
Fixed support of non-ASCII names in functions :func:`!msilib.OpenDatabase`
|
||||
and :func:`!msilib.init_database` and non-ASCII SQL in method
|
||||
:meth:`!msilib.Database.OpenView`.
|
||||
|
||||
..
|
||||
|
||||
|
|
|
@ -5400,7 +5400,7 @@ Update libffi to 3.4.3
|
|||
.. nonce: kV4K_1
|
||||
.. section: Windows
|
||||
|
||||
Fixes a potential buffer overrun in :mod:`msilib`.
|
||||
Fixes a potential buffer overrun in :mod:`!msilib`.
|
||||
|
||||
..
|
||||
|
||||
|
|
|
@ -294,7 +294,7 @@ by Nir Soffer.
|
|||
.. nonce: Nj3A0x
|
||||
.. section: Library
|
||||
|
||||
Make :meth:`msilib.SummaryInformation.GetProperty` return ``None`` when the
|
||||
Make :meth:`!msilib.SummaryInformation.GetProperty` return ``None`` when the
|
||||
value of property is ``VT_EMPTY``. Initial patch by Mark Mc Mahon.
|
||||
|
||||
..
|
||||
|
@ -316,7 +316,7 @@ Initial patch by Robin Wellner.
|
|||
.. nonce: xWT9k0
|
||||
.. section: Library
|
||||
|
||||
:func:`msilib.OpenDatabase` now raises a better exception message when it
|
||||
:func:`!msilib.OpenDatabase` now raises a better exception message when it
|
||||
couldn't open or create an MSI file. Initial patch by William Tisäter.
|
||||
|
||||
..
|
||||
|
|
|
@ -350,7 +350,7 @@ the left most segment of hostname in second argument of
|
|||
.. nonce: Nj3A0x
|
||||
.. section: Library
|
||||
|
||||
Make :meth:`msilib.SummaryInformation.GetProperty` return ``None`` when the
|
||||
Make :meth:`!msilib.SummaryInformation.GetProperty` return ``None`` when the
|
||||
value of property is ``VT_EMPTY``. Initial patch by Mark Mc Mahon.
|
||||
|
||||
..
|
||||
|
@ -396,7 +396,7 @@ Initial patch by Robin Wellner.
|
|||
.. nonce: xWT9k0
|
||||
.. section: Library
|
||||
|
||||
:func:`msilib.OpenDatabase` now raises a better exception message when it
|
||||
:func:`!msilib.OpenDatabase` now raises a better exception message when it
|
||||
couldn't open or create an MSI file. Initial patch by William Tisäter.
|
||||
|
||||
..
|
||||
|
|
|
@ -509,7 +509,7 @@ Add SSLContext.num_tickets to control the number of TLSv1.3 session tickets.
|
|||
.. nonce: nobzc9
|
||||
.. section: Library
|
||||
|
||||
Fix the error handling in :meth:`msilib.SummaryInformation.GetProperty`.
|
||||
Fix the error handling in :meth:`!msilib.SummaryInformation.GetProperty`.
|
||||
Patch by Zackery Spytz.
|
||||
|
||||
..
|
||||
|
@ -538,7 +538,7 @@ module.
|
|||
.. nonce: TQFOR4
|
||||
.. section: Library
|
||||
|
||||
:meth:`msilib.Directory.start_component()` no longer fails if *keyfile* is
|
||||
:meth:`!msilib.Directory.start_component()` no longer fails if *keyfile* is
|
||||
not ``None``.
|
||||
|
||||
..
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
:pep:`594`: Removed the :mod:`!msilib` package, deprecated in Python 3.11.
|
|
@ -1,698 +0,0 @@
|
|||
/*[clinic input]
|
||||
preserve
|
||||
[clinic start generated code]*/
|
||||
|
||||
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
|
||||
# include "pycore_gc.h" // PyGC_Head
|
||||
# include "pycore_runtime.h" // _Py_ID()
|
||||
#endif
|
||||
|
||||
|
||||
PyDoc_STRVAR(_msi_UuidCreate__doc__,
|
||||
"UuidCreate($module, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return the string representation of a new unique identifier.");
|
||||
|
||||
#define _MSI_UUIDCREATE_METHODDEF \
|
||||
{"UuidCreate", (PyCFunction)_msi_UuidCreate, METH_NOARGS, _msi_UuidCreate__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_UuidCreate_impl(PyObject *module);
|
||||
|
||||
static PyObject *
|
||||
_msi_UuidCreate(PyObject *module, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return _msi_UuidCreate_impl(module);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_FCICreate__doc__,
|
||||
"FCICreate($module, cabname, files, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Create a new CAB file.\n"
|
||||
"\n"
|
||||
" cabname\n"
|
||||
" the name of the CAB file\n"
|
||||
" files\n"
|
||||
" a list of tuples, each containing the name of the file on disk,\n"
|
||||
" and the name of the file inside the CAB file");
|
||||
|
||||
#define _MSI_FCICREATE_METHODDEF \
|
||||
{"FCICreate", _PyCFunction_CAST(_msi_FCICreate), METH_FASTCALL, _msi_FCICreate__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_FCICreate_impl(PyObject *module, const char *cabname, PyObject *files);
|
||||
|
||||
static PyObject *
|
||||
_msi_FCICreate(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
const char *cabname;
|
||||
PyObject *files;
|
||||
|
||||
if (!_PyArg_CheckPositional("FCICreate", nargs, 2, 2)) {
|
||||
goto exit;
|
||||
}
|
||||
if (!PyUnicode_Check(args[0])) {
|
||||
_PyArg_BadArgument("FCICreate", "argument 1", "str", args[0]);
|
||||
goto exit;
|
||||
}
|
||||
Py_ssize_t cabname_length;
|
||||
cabname = PyUnicode_AsUTF8AndSize(args[0], &cabname_length);
|
||||
if (cabname == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
if (strlen(cabname) != (size_t)cabname_length) {
|
||||
PyErr_SetString(PyExc_ValueError, "embedded null character");
|
||||
goto exit;
|
||||
}
|
||||
files = args[1];
|
||||
return_value = _msi_FCICreate_impl(module, cabname, files);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_Database_Close__doc__,
|
||||
"Close($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Close the database object.");
|
||||
|
||||
#define _MSI_DATABASE_CLOSE_METHODDEF \
|
||||
{"Close", (PyCFunction)_msi_Database_Close, METH_NOARGS, _msi_Database_Close__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_Database_Close_impl(msiobj *self);
|
||||
|
||||
static PyObject *
|
||||
_msi_Database_Close(msiobj *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return _msi_Database_Close_impl(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_Record_GetFieldCount__doc__,
|
||||
"GetFieldCount($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return the number of fields of the record.");
|
||||
|
||||
#define _MSI_RECORD_GETFIELDCOUNT_METHODDEF \
|
||||
{"GetFieldCount", (PyCFunction)_msi_Record_GetFieldCount, METH_NOARGS, _msi_Record_GetFieldCount__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_Record_GetFieldCount_impl(msiobj *self);
|
||||
|
||||
static PyObject *
|
||||
_msi_Record_GetFieldCount(msiobj *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return _msi_Record_GetFieldCount_impl(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_Record_GetInteger__doc__,
|
||||
"GetInteger($self, field, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return the value of field as an integer where possible.");
|
||||
|
||||
#define _MSI_RECORD_GETINTEGER_METHODDEF \
|
||||
{"GetInteger", (PyCFunction)_msi_Record_GetInteger, METH_O, _msi_Record_GetInteger__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_Record_GetInteger_impl(msiobj *self, unsigned int field);
|
||||
|
||||
static PyObject *
|
||||
_msi_Record_GetInteger(msiobj *self, PyObject *arg)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
unsigned int field;
|
||||
|
||||
field = (unsigned int)PyLong_AsUnsignedLongMask(arg);
|
||||
if (field == (unsigned int)-1 && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _msi_Record_GetInteger_impl(self, field);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_Record_GetString__doc__,
|
||||
"GetString($self, field, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return the value of field as a string where possible.");
|
||||
|
||||
#define _MSI_RECORD_GETSTRING_METHODDEF \
|
||||
{"GetString", (PyCFunction)_msi_Record_GetString, METH_O, _msi_Record_GetString__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_Record_GetString_impl(msiobj *self, unsigned int field);
|
||||
|
||||
static PyObject *
|
||||
_msi_Record_GetString(msiobj *self, PyObject *arg)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
unsigned int field;
|
||||
|
||||
field = (unsigned int)PyLong_AsUnsignedLongMask(arg);
|
||||
if (field == (unsigned int)-1 && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _msi_Record_GetString_impl(self, field);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_Record_ClearData__doc__,
|
||||
"ClearData($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Set all fields of the record to 0.");
|
||||
|
||||
#define _MSI_RECORD_CLEARDATA_METHODDEF \
|
||||
{"ClearData", (PyCFunction)_msi_Record_ClearData, METH_NOARGS, _msi_Record_ClearData__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_Record_ClearData_impl(msiobj *self);
|
||||
|
||||
static PyObject *
|
||||
_msi_Record_ClearData(msiobj *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return _msi_Record_ClearData_impl(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_Record_SetString__doc__,
|
||||
"SetString($self, field, value, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Set field to a string value.");
|
||||
|
||||
#define _MSI_RECORD_SETSTRING_METHODDEF \
|
||||
{"SetString", _PyCFunction_CAST(_msi_Record_SetString), METH_FASTCALL, _msi_Record_SetString__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_Record_SetString_impl(msiobj *self, int field, const Py_UNICODE *value);
|
||||
|
||||
static PyObject *
|
||||
_msi_Record_SetString(msiobj *self, PyObject *const *args, Py_ssize_t nargs)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
int field;
|
||||
const Py_UNICODE *value = NULL;
|
||||
|
||||
if (!_PyArg_CheckPositional("SetString", nargs, 2, 2)) {
|
||||
goto exit;
|
||||
}
|
||||
field = _PyLong_AsInt(args[0]);
|
||||
if (field == -1 && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
if (!PyUnicode_Check(args[1])) {
|
||||
_PyArg_BadArgument("SetString", "argument 2", "str", args[1]);
|
||||
goto exit;
|
||||
}
|
||||
value = PyUnicode_AsWideCharString(args[1], NULL);
|
||||
if (value == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _msi_Record_SetString_impl(self, field, value);
|
||||
|
||||
exit:
|
||||
/* Cleanup for value */
|
||||
PyMem_Free((void *)value);
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_Record_SetStream__doc__,
|
||||
"SetStream($self, field, value, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Set field to the contents of the file named value.");
|
||||
|
||||
#define _MSI_RECORD_SETSTREAM_METHODDEF \
|
||||
{"SetStream", _PyCFunction_CAST(_msi_Record_SetStream), METH_FASTCALL, _msi_Record_SetStream__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_Record_SetStream_impl(msiobj *self, int field, const Py_UNICODE *value);
|
||||
|
||||
static PyObject *
|
||||
_msi_Record_SetStream(msiobj *self, PyObject *const *args, Py_ssize_t nargs)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
int field;
|
||||
const Py_UNICODE *value = NULL;
|
||||
|
||||
if (!_PyArg_CheckPositional("SetStream", nargs, 2, 2)) {
|
||||
goto exit;
|
||||
}
|
||||
field = _PyLong_AsInt(args[0]);
|
||||
if (field == -1 && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
if (!PyUnicode_Check(args[1])) {
|
||||
_PyArg_BadArgument("SetStream", "argument 2", "str", args[1]);
|
||||
goto exit;
|
||||
}
|
||||
value = PyUnicode_AsWideCharString(args[1], NULL);
|
||||
if (value == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _msi_Record_SetStream_impl(self, field, value);
|
||||
|
||||
exit:
|
||||
/* Cleanup for value */
|
||||
PyMem_Free((void *)value);
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_Record_SetInteger__doc__,
|
||||
"SetInteger($self, field, value, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Set field to an integer value.");
|
||||
|
||||
#define _MSI_RECORD_SETINTEGER_METHODDEF \
|
||||
{"SetInteger", _PyCFunction_CAST(_msi_Record_SetInteger), METH_FASTCALL, _msi_Record_SetInteger__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_Record_SetInteger_impl(msiobj *self, int field, int value);
|
||||
|
||||
static PyObject *
|
||||
_msi_Record_SetInteger(msiobj *self, PyObject *const *args, Py_ssize_t nargs)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
int field;
|
||||
int value;
|
||||
|
||||
if (!_PyArg_CheckPositional("SetInteger", nargs, 2, 2)) {
|
||||
goto exit;
|
||||
}
|
||||
field = _PyLong_AsInt(args[0]);
|
||||
if (field == -1 && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
value = _PyLong_AsInt(args[1]);
|
||||
if (value == -1 && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _msi_Record_SetInteger_impl(self, field, value);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_SummaryInformation_GetProperty__doc__,
|
||||
"GetProperty($self, field, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a property of the summary.\n"
|
||||
"\n"
|
||||
" field\n"
|
||||
" the name of the property, one of the PID_* constants");
|
||||
|
||||
#define _MSI_SUMMARYINFORMATION_GETPROPERTY_METHODDEF \
|
||||
{"GetProperty", (PyCFunction)_msi_SummaryInformation_GetProperty, METH_O, _msi_SummaryInformation_GetProperty__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_SummaryInformation_GetProperty_impl(msiobj *self, int field);
|
||||
|
||||
static PyObject *
|
||||
_msi_SummaryInformation_GetProperty(msiobj *self, PyObject *arg)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
int field;
|
||||
|
||||
field = _PyLong_AsInt(arg);
|
||||
if (field == -1 && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _msi_SummaryInformation_GetProperty_impl(self, field);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_SummaryInformation_GetPropertyCount__doc__,
|
||||
"GetPropertyCount($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return the number of summary properties.");
|
||||
|
||||
#define _MSI_SUMMARYINFORMATION_GETPROPERTYCOUNT_METHODDEF \
|
||||
{"GetPropertyCount", (PyCFunction)_msi_SummaryInformation_GetPropertyCount, METH_NOARGS, _msi_SummaryInformation_GetPropertyCount__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_SummaryInformation_GetPropertyCount_impl(msiobj *self);
|
||||
|
||||
static PyObject *
|
||||
_msi_SummaryInformation_GetPropertyCount(msiobj *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return _msi_SummaryInformation_GetPropertyCount_impl(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_SummaryInformation_SetProperty__doc__,
|
||||
"SetProperty($self, field, value, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Set a property.\n"
|
||||
"\n"
|
||||
" field\n"
|
||||
" the name of the property, one of the PID_* constants\n"
|
||||
" value\n"
|
||||
" the new value of the property (integer or string)");
|
||||
|
||||
#define _MSI_SUMMARYINFORMATION_SETPROPERTY_METHODDEF \
|
||||
{"SetProperty", _PyCFunction_CAST(_msi_SummaryInformation_SetProperty), METH_FASTCALL, _msi_SummaryInformation_SetProperty__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_SummaryInformation_SetProperty_impl(msiobj *self, int field,
|
||||
PyObject *data);
|
||||
|
||||
static PyObject *
|
||||
_msi_SummaryInformation_SetProperty(msiobj *self, PyObject *const *args, Py_ssize_t nargs)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
int field;
|
||||
PyObject *data;
|
||||
|
||||
if (!_PyArg_CheckPositional("SetProperty", nargs, 2, 2)) {
|
||||
goto exit;
|
||||
}
|
||||
field = _PyLong_AsInt(args[0]);
|
||||
if (field == -1 && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
data = args[1];
|
||||
return_value = _msi_SummaryInformation_SetProperty_impl(self, field, data);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_SummaryInformation_Persist__doc__,
|
||||
"Persist($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Write the modified properties to the summary information stream.");
|
||||
|
||||
#define _MSI_SUMMARYINFORMATION_PERSIST_METHODDEF \
|
||||
{"Persist", (PyCFunction)_msi_SummaryInformation_Persist, METH_NOARGS, _msi_SummaryInformation_Persist__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_SummaryInformation_Persist_impl(msiobj *self);
|
||||
|
||||
static PyObject *
|
||||
_msi_SummaryInformation_Persist(msiobj *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return _msi_SummaryInformation_Persist_impl(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_View_Execute__doc__,
|
||||
"Execute($self, params, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Execute the SQL query of the view.\n"
|
||||
"\n"
|
||||
" params\n"
|
||||
" a record describing actual values of the parameter tokens\n"
|
||||
" in the query or None");
|
||||
|
||||
#define _MSI_VIEW_EXECUTE_METHODDEF \
|
||||
{"Execute", (PyCFunction)_msi_View_Execute, METH_O, _msi_View_Execute__doc__},
|
||||
|
||||
PyDoc_STRVAR(_msi_View_Fetch__doc__,
|
||||
"Fetch($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a result record of the query.");
|
||||
|
||||
#define _MSI_VIEW_FETCH_METHODDEF \
|
||||
{"Fetch", (PyCFunction)_msi_View_Fetch, METH_NOARGS, _msi_View_Fetch__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_View_Fetch_impl(msiobj *self);
|
||||
|
||||
static PyObject *
|
||||
_msi_View_Fetch(msiobj *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return _msi_View_Fetch_impl(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_View_GetColumnInfo__doc__,
|
||||
"GetColumnInfo($self, kind, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a record describing the columns of the view.\n"
|
||||
"\n"
|
||||
" kind\n"
|
||||
" MSICOLINFO_NAMES or MSICOLINFO_TYPES");
|
||||
|
||||
#define _MSI_VIEW_GETCOLUMNINFO_METHODDEF \
|
||||
{"GetColumnInfo", (PyCFunction)_msi_View_GetColumnInfo, METH_O, _msi_View_GetColumnInfo__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_View_GetColumnInfo_impl(msiobj *self, int kind);
|
||||
|
||||
static PyObject *
|
||||
_msi_View_GetColumnInfo(msiobj *self, PyObject *arg)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
int kind;
|
||||
|
||||
kind = _PyLong_AsInt(arg);
|
||||
if (kind == -1 && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _msi_View_GetColumnInfo_impl(self, kind);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_View_Modify__doc__,
|
||||
"Modify($self, kind, data, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Modify the view.\n"
|
||||
"\n"
|
||||
" kind\n"
|
||||
" one of the MSIMODIFY_* constants\n"
|
||||
" data\n"
|
||||
" a record describing the new data");
|
||||
|
||||
#define _MSI_VIEW_MODIFY_METHODDEF \
|
||||
{"Modify", _PyCFunction_CAST(_msi_View_Modify), METH_FASTCALL, _msi_View_Modify__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_View_Modify_impl(msiobj *self, int kind, PyObject *data);
|
||||
|
||||
static PyObject *
|
||||
_msi_View_Modify(msiobj *self, PyObject *const *args, Py_ssize_t nargs)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
int kind;
|
||||
PyObject *data;
|
||||
|
||||
if (!_PyArg_CheckPositional("Modify", nargs, 2, 2)) {
|
||||
goto exit;
|
||||
}
|
||||
kind = _PyLong_AsInt(args[0]);
|
||||
if (kind == -1 && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
data = args[1];
|
||||
return_value = _msi_View_Modify_impl(self, kind, data);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_View_Close__doc__,
|
||||
"Close($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Close the view.");
|
||||
|
||||
#define _MSI_VIEW_CLOSE_METHODDEF \
|
||||
{"Close", (PyCFunction)_msi_View_Close, METH_NOARGS, _msi_View_Close__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_View_Close_impl(msiobj *self);
|
||||
|
||||
static PyObject *
|
||||
_msi_View_Close(msiobj *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return _msi_View_Close_impl(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_Database_OpenView__doc__,
|
||||
"OpenView($self, sql, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a view object.\n"
|
||||
"\n"
|
||||
" sql\n"
|
||||
" the SQL statement to execute");
|
||||
|
||||
#define _MSI_DATABASE_OPENVIEW_METHODDEF \
|
||||
{"OpenView", (PyCFunction)_msi_Database_OpenView, METH_O, _msi_Database_OpenView__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_Database_OpenView_impl(msiobj *self, const Py_UNICODE *sql);
|
||||
|
||||
static PyObject *
|
||||
_msi_Database_OpenView(msiobj *self, PyObject *arg)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
const Py_UNICODE *sql = NULL;
|
||||
|
||||
if (!PyUnicode_Check(arg)) {
|
||||
_PyArg_BadArgument("OpenView", "argument", "str", arg);
|
||||
goto exit;
|
||||
}
|
||||
sql = PyUnicode_AsWideCharString(arg, NULL);
|
||||
if (sql == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _msi_Database_OpenView_impl(self, sql);
|
||||
|
||||
exit:
|
||||
/* Cleanup for sql */
|
||||
PyMem_Free((void *)sql);
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_Database_Commit__doc__,
|
||||
"Commit($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Commit the changes pending in the current transaction.");
|
||||
|
||||
#define _MSI_DATABASE_COMMIT_METHODDEF \
|
||||
{"Commit", (PyCFunction)_msi_Database_Commit, METH_NOARGS, _msi_Database_Commit__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_Database_Commit_impl(msiobj *self);
|
||||
|
||||
static PyObject *
|
||||
_msi_Database_Commit(msiobj *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return _msi_Database_Commit_impl(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_Database_GetSummaryInformation__doc__,
|
||||
"GetSummaryInformation($self, count, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a new summary information object.\n"
|
||||
"\n"
|
||||
" count\n"
|
||||
" the maximum number of updated values");
|
||||
|
||||
#define _MSI_DATABASE_GETSUMMARYINFORMATION_METHODDEF \
|
||||
{"GetSummaryInformation", (PyCFunction)_msi_Database_GetSummaryInformation, METH_O, _msi_Database_GetSummaryInformation__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_Database_GetSummaryInformation_impl(msiobj *self, int count);
|
||||
|
||||
static PyObject *
|
||||
_msi_Database_GetSummaryInformation(msiobj *self, PyObject *arg)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
int count;
|
||||
|
||||
count = _PyLong_AsInt(arg);
|
||||
if (count == -1 && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _msi_Database_GetSummaryInformation_impl(self, count);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_OpenDatabase__doc__,
|
||||
"OpenDatabase($module, path, persist, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a new database object.\n"
|
||||
"\n"
|
||||
" path\n"
|
||||
" the file name of the MSI file\n"
|
||||
" persist\n"
|
||||
" the persistence mode");
|
||||
|
||||
#define _MSI_OPENDATABASE_METHODDEF \
|
||||
{"OpenDatabase", _PyCFunction_CAST(_msi_OpenDatabase), METH_FASTCALL, _msi_OpenDatabase__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_OpenDatabase_impl(PyObject *module, const Py_UNICODE *path, int persist);
|
||||
|
||||
static PyObject *
|
||||
_msi_OpenDatabase(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
const Py_UNICODE *path = NULL;
|
||||
int persist;
|
||||
|
||||
if (!_PyArg_CheckPositional("OpenDatabase", nargs, 2, 2)) {
|
||||
goto exit;
|
||||
}
|
||||
if (!PyUnicode_Check(args[0])) {
|
||||
_PyArg_BadArgument("OpenDatabase", "argument 1", "str", args[0]);
|
||||
goto exit;
|
||||
}
|
||||
path = PyUnicode_AsWideCharString(args[0], NULL);
|
||||
if (path == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
persist = _PyLong_AsInt(args[1]);
|
||||
if (persist == -1 && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _msi_OpenDatabase_impl(module, path, persist);
|
||||
|
||||
exit:
|
||||
/* Cleanup for path */
|
||||
PyMem_Free((void *)path);
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(_msi_CreateRecord__doc__,
|
||||
"CreateRecord($module, count, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a new record object.\n"
|
||||
"\n"
|
||||
" count\n"
|
||||
" the number of fields of the record");
|
||||
|
||||
#define _MSI_CREATERECORD_METHODDEF \
|
||||
{"CreateRecord", (PyCFunction)_msi_CreateRecord, METH_O, _msi_CreateRecord__doc__},
|
||||
|
||||
static PyObject *
|
||||
_msi_CreateRecord_impl(PyObject *module, int count);
|
||||
|
||||
static PyObject *
|
||||
_msi_CreateRecord(PyObject *module, PyObject *arg)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
int count;
|
||||
|
||||
count = _PyLong_AsInt(arg);
|
||||
if (count == -1 && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _msi_CreateRecord_impl(module, count);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
/*[clinic end generated code: output=7d083c61679eed83 input=a9049054013a1b77]*/
|
|
@ -1,115 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|ARM">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ARM</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|ARM64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="PGInstrument|ARM">
|
||||
<Configuration>PGInstrument</Configuration>
|
||||
<Platform>ARM</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="PGInstrument|ARM64">
|
||||
<Configuration>PGInstrument</Configuration>
|
||||
<Platform>ARM4</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="PGInstrument|Win32">
|
||||
<Configuration>PGInstrument</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="PGInstrument|x64">
|
||||
<Configuration>PGInstrument</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="PGUpdate|ARM">
|
||||
<Configuration>PGUpdate</Configuration>
|
||||
<Platform>ARM</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="PGUpdate|ARM64">
|
||||
<Configuration>PGUpdate</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="PGUpdate|Win32">
|
||||
<Configuration>PGUpdate</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="PGUpdate|x64">
|
||||
<Configuration>PGUpdate</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ARM">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ARM</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ARM64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{31FFC478-7B4A-43E8-9954-8D03E2187E9C}</ProjectGuid>
|
||||
<RootNamespace>_msi</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<SupportPGO>false</SupportPGO>
|
||||
</PropertyGroup>
|
||||
<Import Project="python.props" />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<PropertyGroup>
|
||||
<TargetExt>.pyd</TargetExt>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="pyproject.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<AdditionalDependencies>cabinet.lib;msi.lib;rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\PC\_msi.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\PC\python_nt.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="pythoncore.vcxproj">
|
||||
<Project>{cf7ac3d1-e2df-41d2-bea6-1e2556cdea26}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -1,21 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{bdef7710-e433-4ac0-84e0-14f34454bd3e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{8513f324-7c13-4657-b463-5d686a8a5371}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\PC\_msi.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\PC\python_nt.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -64,7 +64,7 @@
|
|||
<!-- pyshellext.dll -->
|
||||
<Projects Include="pyshellext.vcxproj" />
|
||||
<!-- Extension modules -->
|
||||
<ExtensionModules Include="_asyncio;_zoneinfo;_decimal;_elementtree;_msi;_multiprocessing;_overlapped;pyexpat;_queue;select;unicodedata;winsound;_uuid;_wmi" />
|
||||
<ExtensionModules Include="_asyncio;_zoneinfo;_decimal;_elementtree;_multiprocessing;_overlapped;pyexpat;_queue;select;unicodedata;winsound;_uuid;_wmi" />
|
||||
<ExtensionModules Include="_ctypes" Condition="$(IncludeCTypes)" />
|
||||
<!-- Extension modules that require external sources -->
|
||||
<ExternalModules Include="_bz2;_lzma;_sqlite3" />
|
||||
|
|
|
@ -68,8 +68,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_ctypes_test", "_ctypes_tes
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_elementtree", "_elementtree.vcxproj", "{17E1E049-C309-4D79-843F-AE483C264AEA}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_msi", "_msi.vcxproj", "{31FFC478-7B4A-43E8-9954-8D03E2187E9C}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_socket", "_socket.vcxproj", "{86937F53-C189-40EF-8CE8-8759D8E7D480}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_sqlite3", "_sqlite3.vcxproj", "{13CECB97-4119-4316-9D42-8534019A5A44}"
|
||||
|
|
|
@ -138,7 +138,6 @@ _zoneinfo
|
|||
_decimal
|
||||
_elementtree
|
||||
_hashlib
|
||||
_msi
|
||||
_multiprocessing
|
||||
_overlapped
|
||||
_socket
|
||||
|
|
|
@ -45,7 +45,6 @@ static const char* _Py_stdlib_module_names[] = {
|
|||
"_lzma",
|
||||
"_markupbase",
|
||||
"_md5",
|
||||
"_msi",
|
||||
"_multibytecodec",
|
||||
"_multiprocessing",
|
||||
"_opcode",
|
||||
|
@ -180,7 +179,6 @@ static const char* _Py_stdlib_module_names[] = {
|
|||
"mimetypes",
|
||||
"mmap",
|
||||
"modulefinder",
|
||||
"msilib",
|
||||
"msvcrt",
|
||||
"multiprocessing",
|
||||
"netrc",
|
||||
|
|
|
@ -50,7 +50,6 @@ CORE_MODULES = {
|
|||
|
||||
# Windows-only modules
|
||||
WINDOWS_MODULES = {
|
||||
"_msi",
|
||||
"_overlapped",
|
||||
"_testconsole",
|
||||
"_winapi",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<?define exts=pyexpat;select;unicodedata;winsound;_bz2;_elementtree;_socket;_ssl;_msi;_ctypes;_hashlib;_multiprocessing;_lzma;_decimal;_overlapped;_sqlite3;_asyncio;_queue;_uuid;_wmi;_zoneinfo ?>
|
||||
<?define exts=pyexpat;select;unicodedata;winsound;_bz2;_elementtree;_socket;_ssl;_ctypes;_hashlib;_multiprocessing;_lzma;_decimal;_overlapped;_sqlite3;_asyncio;_queue;_uuid;_wmi;_zoneinfo ?>
|
||||
<Fragment>
|
||||
<DirectoryRef Id="Lib_venv_scripts_nt" />
|
||||
|
||||
|
|
|
@ -56,7 +56,6 @@ OMIT_FILES = (
|
|||
"concurrent/futures/thread.py",
|
||||
# Misc unused or large files
|
||||
"pydoc_data/",
|
||||
"msilib/",
|
||||
)
|
||||
|
||||
# Synchronous network I/O and protocols are not supported; for example,
|
||||
|
|
Loading…
Reference in New Issue