Bases: object
Base class for other recipes.
It implements notably fetching of the main software part plus addons.
The sources attribute is a dict storing how to fetch the main software part and the specified addons, with the following structure:
local path -> (type, location_spec, options), in which:
local path: is either the main_software singleton (see MainSoftware) or a local path to an addons directory.
type: can be either
- 'local'
- 'downloadable'
- one of the supported vcs
location_spec: is, depending on the type, a tuple specifying how fetch is to be done:
url, or (vcs_url, vcs_revision) or None
addons options: are typically used to specify that the addons directory is actually a subdir of the specified one.
VCS support classes (see anybox.recipe.odoo.vcs) can implemented their dedicated options
The merges attribute is a dict storing how to fetch additional changes to merge into VCS type sources:
local path -> [(type, location_spec, options), ... ]
See sources for the meaning of the various components. Note that in merges, values are a list of triples instead of only a single triple as values in sources because there can be multiple merges on the same local path.
Store some booleans depending on detected version.
To be refined by subclasses.
Revert local modifications that have been made during installation.
These can be, e.g., forbidden by the freeze process.
Develop the specified source distribution.
Any call to zc.recipe.eggs will use that developped version. develop() launches a subprocess, to which we need to forward the paths to requirements via PYTHONPATH.
Parameters: | setup_has_pil – if True, an altered version of setup that does not require PIL is produced to perform the develop, so that installation can be done with Pillow instead. Recent enough versions of OpenERP/Odoo are directly based on Pillow. |
---|---|
Returns: | project name of the distribution that’s been “developed” This is useful for OpenERP/Odoo itself, whose project name changed within the 8.0 stable branch. |
After download/analysis of ‘nightly latest’, give equivalent spec.
Extract anything that has been downloaded to target_dir.
This doesn’t copy intermediary buildout configurations nor local parts. In the purpose of making a self-contained and offline playable archive, these are assumed to be already taken care of.
Add implicit paths and serialize in the addons_path option.
Parameters: | check_existence – if True, all the paths will be checked for existence (useful for unit tests) |
---|
Create an extension buildout freezing current revisions & versions.
Insert the standard, non-base addons bundled within Odoo git repo.
See lp:1327756
These addons are also part of the Github branch for prior versions, therefore we cannot rely on version knowledge; we check for existence instead. If not found (e.g, we are on a nightly for OpenERP <= 7), this method does nothing.
The ordering of the different paths of addons is important. When several addons at different paths have the same name, the first of them being found is used. This can be used, for instance, to replace an official addon by another one by placing a different addons’ path before the official one.
If the official addons’ path is already set in the config file (e.g. at the end), it will leave it at the end of the paths list, if it is not set, it will be placed at the beginning just after base addons’ path.
Care is taken not to break configurations that corrected this manually with a local source in the addons option.
Parameters: | base_addons – the path to previously detected base addons, to properly insert right after them |
---|
Install egg requirements and scripts.
If some distributions are known as soft requirements, will retry without them
True if this is the git layout, as seen from the move to GitHub.
In this layout, the standard addons other than base are in a addons directory right next to the openerp package.
Tell if the download is stale by doing a HEAD request.
Assumes the correct date had been written upon download. This is the same system as in GNU Wget 1.12. It works even if the server does not implement conditional responses such as 304
Make a path absolute if needed.
If not already absolute, it is interpreted as relative to the buildout directory.
Base URLs to look for nightly versions.
The URL for 8.0 may have to be adapted once it’s released for good. This one is guessed from 7.0 and is needed by unit tests.
Parse the addons options into sources.
See BaseRecipe for the structure of sources.
Parse the merge options into merges.
See BaseRecipe for the structure of merges.
Parse revisions options and update sources.
It is assumed that sources has already been populated, and notably has a main_software entry. This allows for easy fixing of revisions in an extension buildout
See BaseRecipe for the structure of sources.
Perform version checks before any attempt to install.
To be subclassed.
Ugly method to extract requirements & version from ugly setup.py.
Primarily designed for 6.0, but works with 6.1 as well.
Try and read the release.py file directly.
Used as a fallback in case reading setup.py failed, which happened in an old OpenERP version. Could become the norm, but setup is also used to list dependencies.
Base URLs to look for official, released versions.
There are currently no official releases for Odoo, but the recipe has been designed at the time of OpenERP 6.0 and some parts of its code at least expect this dict to exist. Besides, official releases may reappear at some point.
Peform all lookup and downloads specified in sources.
See BaseRecipe for the structure of sources.
Lookup or fetch the main software.
See MainSoftware and BaseRecipe for explanations.
Extract those members that are below the tarfile path ‘sandbox’.
The tarfile module official doc warns against attacks with .. in tar.
The option to start with a first member is useful for this case, since the recipe consumes a first member in the tar file to get the openerp main directory in parts. It is taken for granted that this first member has already been checked.
Bases: object
Placeholder to represent the main software instead of an addon location.
Should just have a singleton instance: main_software, whose meaning depends on the concrete recipe class using it.
For example, in anybox.recipe.odoo.server.ServerRecipe, main_software represents the OpenObject server or the OpenERP standard distribution.
Provide devtools to openerp.
Bases: anybox.recipe.odoo.base.BaseRecipe
Recipe for server install and config
Store some booleans depending on detected version.
Also does some options normalization accordingly. Currently, there is only one Odoo version, this method will be really useful again in a while.
Prepare for installation by zc.recipe.egg
- develop the openerp distribution and require it
- gunicorn’s related dependencies if needed
Once ‘openerp’ is required, zc.recipe.egg will take it into account and put it in needed scripts, interpreters etc.
Historically, in anybox.recipe.openerp this used to take care of adding Pillow, which is now in Odoo’s setup.py.
Name of expected nightly tarballs in base URL, by major version.
Utilities for unit tests.
Bases: anybox.recipe.odoo.vcs.base.BaseRepo
Bases: anybox.recipe.odoo.testing.FakeRepo
A variant of FakeRepo that still needs the directory structure around.
Makes for a more realistic test of some conditions. In particular, reproduced launchpad #TODO
Bases: unittest.case.TestCase
A base setup for tests of recipe classes
Bases: anybox.recipe.odoo.base.BaseRecipe
A subclass with just enough few defaults for unit testing.
Bases: object
A context manager to get back the working directory as it was before.
If you want to stack working directory keepers, you need a new instance for each stage.
Backport of subprocess.check_output from python 2.7.
Example (this doctest would be more readable with ELLIPSIS, but that’s good enough for today):
>>> out = check_output(["ls", "-l", "/dev/null"])
>>> out.startswith('crw-rw-rw')
True
The stdout argument is not allowed as it is used internally. To capture standard error in the result, use stderr=STDOUT.
>>> os.environ['LANG'] = 'C' # for uniformity of error msg
>>> err = check_output(["/bin/sh", "-c",
... "ls -l non_existent_file ; exit 0"],
... stderr=subprocess.STDOUT)
>>> err.strip().endswith("No such file or directory")
True
Recursively remove object files in given directory.
Also remove resulting empty directories.
True if given filename is a python object file.
The least common denominator of OpenERP versions : two numbers.
OpenERP version numbers are a bit hard to compare if we consider nightly releases, bzr versions etc. It’s almost impossible to compare them without an a priori knowledge of release dates and revisions.
Here are some examples:
>>> major_version('1.2.3-foo.bar')
(1, 2)
>>> major_version('6.1-20121003-233130')
(6, 1)
>>> major_version('7.0alpha')
(7, 0)
Beware, the packaging script does funny things, such as labeling current nightlies as 6.2-date-time whereas version_info is (7, 0, 0, ALPHA) We can in recipe code check for >= (6, 2), that’s not a big issue.
Regarding OpenERP saas releases (e.g. 7.saas~1) that are short-lived stable versions between two “X.0” LTS releases, the ‘saas~’ argument before the minor version number is stripped. For instance:
>>> major_version('7.saas~3')
(7, 3)
Split a multiline option value.
This function performs stripping of whitespaces and allows comments as ConfigParser would do. Namely:
a line starting with a hash is a comment. This is already taken care of by zc.buildout parsing of the configuration file.
ConfigParser does not apply this rule to the case where the hash is after some leading whitespace (e.g, line-continuation indentation) as in this example:
[foo]
bar = line1
line2
# this is a comment
# this is not a comment, and will appear in 'bar' value
Therefore this function does not have to perform anything with respect to hash-comments.
everything after a semicolon following a whitespace is a comment:
[foo]
bar = line1
line2 ;this is a comment
Parameters: | opt_val (basestring) – the raw option value |
---|---|
Returns: | tuple of strings |
doctests (less readable than examples above, but more authoritative):
>>> option_splitlines('line1\n line2 ;this is a comment\n line3')
('line1', 'line2', 'line3')
>>> option_splitlines('l1\n; inline comment from beginning\n line3')
('l1', 'line3')
>>> option_splitlines('l1\n; inline comment from beginning\n line3')
('l1', 'line3')
>>> option_splitlines('l1\n ; disappears after stripping \n line3')
('l1', 'line3')
>>> option_splitlines('line1\n\n')
('line1',)
>>> option_splitlines('')
()
For convenience, None is accepted:
>>> option_splitlines(None)
()
Same as option_splitlines() for a single line.
>>> option_strip(" hey, we have ; a comment")
'hey, we have'
>>> option_strip(None) is None
True
Uniformity backport of datetime.timedelta.total_seconds`()
Parameters: | td – a datetime.timedelta instance |
---|---|
Returns: | the number of seconds in tdelta |
The implementation for Python < 2.7 is taken from the standard library documentation