Git Product home page Git Product logo

wagon's Introduction

Wagon

Build Status Build status PyPI version Supported Python Versions Requirements Status Code Coverage Code Quality Is Wheel

A wagon (also spelt waggon in British and Commonwealth English) is a heavy four-wheeled vehicle pulled by draught animals, used for transporting goods, commodities, agricultural materials, supplies, and sometimes people. Wagons are distinguished from carts, which have two wheels, and from lighter four-wheeled vehicles primarily for carrying people, such as carriages.

or.. it is just a set of (Python) Wheels.

NOTE: To accommodate for the inconsistencies between wagon and pip, and to allow for additional required functionality, we will have to perform breaking changes until we can release v1.0.0. Please make sure you hardcode your wagon versions up until then.

Incentive

Cloudify Plugins are packaged as sets of Python Wheels in tar.gz/zip archives and so we needed a tool to create such entities; hence, Wagon.

Requirements

  • Wagon requires pip 1.4+ to work as this is the first version of pip to support Wheels.
  • Wagon supports Linux, Windows and OSX on Python 2.7 and 3.4+. Python 2.5 will not be supported as it is not supported by pip. Python 2.6.x is not longer supported as wheel itself doesn't support it.
  • Wagon is currently tested on both Linux and Windows (via Travis and AppVeyor).
  • To be able to create Wagons of Wheels which include C extensions on Windows, you must have the C++ Compiler for Python installed.
  • To be able to create Wagons of Wheels which include C extensions on Linux or OSX, you must have the required compiler installed depending on your base distro. Usually:
    • RHEL based required gcc and python-devel.
    • Debian based require gcc and python-dev.
    • Other linux distributions will usually require gcc but might require additional packages.
    • OSX requires gcc.

Installation

pip install wagon

# latest development version
pip install http://github.com/cloudify-cosmo/wagon/archive/master.tar.gz

Backward Compatilibity

NOTE: pip 10.x breaks wagon<=0.7.0 due to the removal of the --use-wheel. If you're using pip>=10.x, please make sure you use wagon>=0.8.0. Also, if you're using pip<=7.x, use wagon<=0.7.0.

NOTE: wagon>=0.7.0 drops support for Python 2.6, 3.2 and 3.3 since Wheel itself no longer supports these versions. Please use wagon<=0.6.1 if you still need to support those versions.

Usage

NOTE: Currently, Wagon allows to pass arbitrary args to pip wheel and pip install. The way in which this is implemented is inconsistent with pip's implementation (wagon just allows passing a -a flag for all args.) This will be changed in the future to correspond to pip's implementation. See #70 for more information.

$ wagon
usage: wagon [-h] [-v] {create,install,validate,show,repair} ...

Create and install wheel based packages with their dependencies

positional arguments:
  {create,install,validate,show,repair}
    create              Create a Wagon archive
    install             Install a Wagon archive
    validate            Validate a wagon archive
    show                Print out the metadata of a wagon
    repair              Repair a Wagon archive

optional arguments:
  -h, --help            show this help message and exit
  -v, --verbose         Set verbose logging level (default: False)

...

Create Packages

$ wagon create flask
...

Creating archive for flask...
Retrieving source...
Source is: Flask
Downloading Wheels for Flask...
Collecting Flask
Using cached Flask-0.12-py2.py3-none-any.whl
Saved /tmp/tmpcYHwh0/Flask/wheels/Flask-0.12-py2.py3-none-any.whl
Collecting itsdangerous>=0.21 (from Flask)
Saved /tmp/tmpcYHwh0/Flask/wheels/itsdangerous-0.24-cp27-none-any.whl
Collecting click>=2.0 (from Flask)
Using cached click-6.7-py2.py3-none-any.whl
Saved /tmp/tmpcYHwh0/Flask/wheels/click-6.7-py2.py3-none-any.whl
...
Skipping MarkupSafe, due to already being wheel.
Platform is: linux_x86_64
Generating Metadata...
Writing metadata to file: /tmp/tmpcYHwh0/Flask/package.json
Creating tgz archive: ./Flask-0.12-py27-none-linux_x86_64.wgn...
Removing work directory...
Wagon created successfully at: ./Flask-0.12-py27-none-linux_x86_64.wgn

...

Requirement Files

NOTE: Beginning with Wagon 0.5.0, Wagon no longer looks up requirement files within archives or in the local directory when creating wagons. You must expclitly specify requirement files.

You can provide multiple requirement files to be resolved by using the -r flag (multiple times).

Editable Mode

Wagon doesn't currently provide a way for packaging packages that are in editable mode. So, for instance, providing a dev-requirements file which contains a -e DEPENDENCY requirement will not be taken into consideration. This is not related to wagon but rather to the default pip wheel implementation stating that it will be "Skipping bdist_wheel for #PACKAGE#, due to being editable".

Install Packages

$ wagon install Flask-0.12-py27-none-linux_x86_64.wgn
...

Installing Flask-0.12-py27-none-linux_x86_64.wgn
Retrieving source...
Extracting tgz Flask-0.12-py27-none-linux_x86_64.wgn to /tmp/tmplXv6Fi...
Source is: /tmp/tmplXv6Fi/Flask
Validating Platform linux_x86_64 is supported...
Installing Flask...
Installing within current virtualenv
Collecting Flask
Collecting itsdangerous>=0.21 (from Flask)
...
Installing collected packages: itsdangerous, Werkzeug, Flask
Successfully installed Flask-0.12 Werkzeug-0.11.15 itsdangerous-0.24

...

NOTE: --pre is appended to the installation command to enable installation of prerelease versions.

Installing Manually

While wagon provides a generic way of installing wagon created archives, you might not want to use the installer as you might not wish to install wagon on your application servers. Installing the package manually via pip is as easy as running (for example):

# For Linux (Windows wagon archives are zip files)
tar -xzvf ./Flask-0.12-py27-none-linux_x86_64.wgn
pip install --no-index --find-links Flask/wheels flask

Validate Packages

The validate function provides shallow validation of a Wagon archive. Basically, that all required wheels for a package are present and that the package is installable.

This shallow validation should, at the very least, verify that a Wagon archive is not corrupted. Note that the --validate flag provided with the create function uses this same validation method. Also note that validation must take place only on an OS distribution which supports the wagon archive if it contains C extensions. For instance, a win32 specific wagon archive will fail to validate on a Linux machine.

venv Python's stdlib module must be installed for Wagon to be able to validate an archive to not pollute the current environment.

$ wagon validate Flask-0.12-py27-none-linux_x86_64.wgn
...

Validating Flask-0.12-py27-none-linux_x86_64.wgn
Retrieving source...
Extracting tgz Flask-0.12-py27-none-linux_x86_64.wgn to /tmp/tmp2gqpy1...
Source is: /tmp/tmp2gqpy1/Flask
Verifying that all required files exist...
Testing package installation...
Creating Virtualenv /tmp/tmpdPNDIi...
Using real prefix '/usr'
New python executable in /tmp/tmpdPNDIi/bin/python2
Also creating executable in /tmp/tmpdPNDIi/bin/python
Installing setuptools, pip, wheel...done.
Installing /tmp/tmp2gqpy1/Flask
Retrieving source...
Source is: /tmp/tmp2gqpy1/Flask
Validating Platform linux_x86_64 is supported...
Installing Flask...
Collecting Flask
...
Installing collected packages: itsdangerous, click, MarkupSafe, Jinja2, Werkzeug, Flask
Successfully installed Flask-0.12 Jinja2-2.9.2 MarkupSafe-0.23 Werkzeug-0.11.15 click-6.7 itsdangerous-0.24
Package Flask is installed in /tmp/tmpdPNDIi
Validation Passed!

...

Show Metadata

Given a Wagon archive, this will print its metadata.

$ wagon show Flask-0.12-py27-none-linux_x86_64.wgn
...

{
    "archive_name": "Flask-0.12-py27-none-linux_x86_64.wgn",
    "build_server_os_properties": {
        "distribution": "antergos",
        "distribution_release": "archcode",
        "distribution_version": ""
    },
    "created_by_wagon_version": "0.6.0",
    "package_name": "Flask",
    "package_source": "flask",
    "package_version": "0.12",
    "supported_platform": "linux_x86_64",
    "supported_python_versions": [
        "py27"
    ],
    "wheels": [
        "MarkupSafe-0.23-cp27-cp27mu-linux_x86_64.whl",
        "Werkzeug-0.11.15-py2.py3-none-any.whl",
        "Jinja2-2.9.2-py2.py3-none-any.whl",
        "click-6.7-py2.py3-none-any.whl",
        "itsdangerous-0.24-cp27-none-any.whl",
        "Flask-0.12-py2.py3-none-any.whl"
    ]
}

...

Repair Wagon

auditwheel is a tool (currently under development) provided by pypa to "repair" wheels to support multiple linux distributions. Information on auditwheel is provided here.

Wagon provides a way to repair a wagon by iterating over its wheels and fixing all of them.

NOTE! The repair command is EXPERIMENTAL in Wagon. It isn't fully tested and relies on auditwheel, which is, in itself, somewhat experimental. Read https://www.python.org/dev/peps/pep-0513/ for more info.

For more information, see Linux Support for compiled wheels below.

The following example was executed on a container provided for wheel-auditing purposes which you can be run like so:

$ docker run -it -v `pwd`:/io quay.io/pypa/manylinux1_x86_64 /bin/bash
$ /opt/python/cp27-cp27m/bin/pip install wagon
...

$ /opt/python/cp27-cp27m/bin/wagon repair cloudify-4.0a10-py27-none-linux_x86_64.wgn -v
...

Repairing: cloudify-4.0a10-py27-none-linux_x86_64.wgn
Retrieving source...
Extracting tgz cloudify-4.0a10-py27-none-linux_x86_64.wgn to /tmp/tmpDZ4kNC...
Source is: /tmp/tmpDZ4kNC/cloudify
Repairing PyYAML-3.10-cp27-cp27m-linux_x86_64.whl
Previous filename tags: linux_x86_64
New filename tags: manylinux1_x86_64
Previous WHEEL info tags: cp27-cp27m-linux_x86_64
New WHEEL info tags: cp27-cp27m-manylinux1_x86_64
...
Generating Metadata...
Writing metadata to file: /tmp/tmpDZ4kNC/cloudify/package.json
Creating tgz archive: /cloudify-4.0a10-py27-none-manylinux1_x86_64.wgn...
Wagon created successfully at: /cloudify-4.0a10-py27-none-manylinux1_x86_64.wgn

...

Naming and Versioning

Source: PyPI

When providing a PyPI source, it can either be supplied as PACKAGE_NAME==PACKAGE_VERSION after which wagon then applies the correct name and version to the archive according to the two parameters; or PACKAGE_NAME, after which the PACKAGE_VERSION will be extracted from the downloaded wheel.

Source: Else

For local path and URL sources, the name and version are automatically extracted from the setup.py file.

NOTE: This means that when supplying a local path, you must supply a path to the root of where your setup.py file resides.

NOTE: If using a URL, it must be a URL to a tar.gz/zip file structured like a GitHub tar.gz/zip archive (e.g. https://github.com/cloudify-cosmo/cloudify-script-plugin/archive/master.tar.gz)

Metadata File and Wheels

A Metadata file is generated for the archive and looks somewhat like this:

{
    "archive_name": "cloudify_script_plugin-1.2-py27-none-linux_x86_64.wgn",
    "build_server_os_properties": {
        "distribution": "ubuntu",
        "distribution_release": "trusty",
        "distribution_version": "14.04"
    },
    "package_name": "cloudify-script-plugin",
    "package_source": "cloudify-script-plugin==1.2",
    "package_version": "1.2",
    "supported_platform": "any",
    "supported_python_versions": [
        "py26",
        "py27"
    ],
    "wheels": [
        "proxy_tools-0.1.0-py2-none-any.whl",
        "pyzmq-14.7.0-cp27-none-linux_x86_64.whl",
        "bottle-0.12.7-py2-none-any.whl",
        "networkx-1.8.1-py2-none-any.whl",
        "requests-2.5.1-py2.py3-none-any.whl",
        "PyYAML-3.10-cp27-none-linux_x86_64.whl",
        "pika-0.9.13-py2-none-any.whl",
        "jsonschema-2.3.0-py2.py3-none-any.whl",
        "cloudify_dsl_parser-3.2-py2-none-any.whl",
        "cloudify_rest_client-3.2-py2-none-any.whl",
        "cloudify_script_plugin-1.2-py2-none-any.whl"
    ]
}
  • The wheels to be installed reside in the zip file under 'wheels/*.whl'.
  • The Metadata file resides in the archive file under 'package.json'.
  • The installer uses the metadata file to check that the platform fits the machine the package is being installed on.
  • OS Properties only appear when creating compiled Linux packages (see Linux Distributions section). In case of a non-linux platform (e.g. win32, any), null values will be supplied for OS properties.
  • The distribution identification is done using platform.linux_distribution, which is deprecated and will be removed in Python 3.7. https://github.com/nir0s/distro is a successor of that functionality and can be installed by running pip install wagon[dist]. We currently use distro only if it is instsalled. In later versions of wagon, we will stop using platform.linux_distribution altogether.

Archive naming convention and Platform

The archive is named according to the Wheel naming convention described in PEP0491.

Example Output Archive: cloudify_aws_plugin-1.4.3-py27-none-any.wgn

  • {python tag}: The Python version is set by the Python running the packaging process. That means that while a package might run on both py27 and py33 (for example), since the packaging process took place using Python 2.7, only py27 will be appended to the name. A user can also explicitly provide the supported Python versions for the package via the pyver flag.
  • {platform tag}: Normally, the platform (e.g. linux_x86_64, win32) is set for each specific wheel. To know which platform the package with its dependencies can be installed on, all wheels are checked. If a specific wheel has a platform property other than any, that platform will be used as the platform of the package. Of course, we assume that there can't be wheels downloaded or created on a specific machine platform that belongs to two different platforms.
  • {abi tag}: Note that the ABI tag is currently ignored and will always be none. This might be changed in the future to support providing an ABI tag.

Linux Support for compiled wheels

Example Output Archive: cloudify_fabric_plugin-1.2.1-py27-none-linux_x86_64.wgn

Wheels which require compilation of C-extensions and are compiled on Linux are not uploaded to PyPI due to variations between compilation environments on different distributions and links to varying system libraries.

To overcome that (partially), when running Wagon on Linux and the package requires compilation, the metadata provides the distribution, version and release name of the OS that the archive was created on (via platform.linux_distribution() and https://github.com/nir0s/distro). Statistically speaking, this should provide the user with the information they need to know which OS the package can be installed on. Obviously, this is not true for cases where non-generic compilation methods are used on the creating OS but otherwise should work, and should specifically always work when both compilation environment and Python version are similar on the creating and installing OS - which, we generally recommend.

What this practically means, is that in most cases using the metadata to compare the distro, distro version, and the Python version under which the package is installed would allow a user to use Wagon rather safely. Of course, Wagon provides no guarantee whatsoever as to whether this will actually work or not and users must test their archives.

That being said, Wagon is completely safe for creating and installing Pure-Python package archives for any platform, and, due to the nature of Wheels, packages compiled for OS X or Windows on corresponding architectures.

Python API

Wagon provides an easy to use API. You can pass a verbose True/False flag to each of these functions.

Create

import wagon

source = 'flask==0.10.1'

wagon.set_verbose(True)

archive_path = wagon.create(
    source,
    requirement_files=None,
    force=False,
    keep_wheels=False,
    archive_destination_dir='.',
    python_versions=None,
    validate_archive=False,
    wheel_args='',
    archive_format='tar.gz')

Install

import wagon

source = 'http://my-wagons.com/Flask-0.10.1-py27-none-linux_x86_64.wgn'

wagon.install(
    source,
    venv=None,
    requirement_files=None,
    upgrade=False,
    ignore_platform=False,
    install_args='')

Validate

import wagon

source = 'http://my-wagons.com/Flask-0.10.1-py27-none-linux_x86_64.wgn'

result = wagon.validate(source=source)  # True if validation successful, else False

Showmeta

import wagon

source = 'http://my-wagons.com/Flask-0.10.1-py27-none-linux_x86_64.wgn'

metadata = wagon.show(source=source)
print(metadata)

Repair

import wagon

source = 'http://my-wagons.com/Flask-0.10.1-py27-none-linux_x86_64.wgn'
repaired_archive_path = wagon.repair(source=source, validate=True)

Testing

NOTE: Running the tests require an internet connection NOTE: Some tests check if the CI env var is set. If not, they will not run.

git clone [email protected]:cloudify-cosmo/wagon.git
cd wagon
pip install tox
tox

Contributions..

..are always welcome. We're looking to:

  • Provide the most statistically robust way of identification and installation of Linux compiled Wheels.

wagon's People

Contributors

adarshaked avatar adrian-polanczyk-codilime avatar ahmadiesa-abu avatar asottile avatar cosmo-admin avatar dankilman avatar earthmant avatar fogelomer avatar gilzellner avatar glukhman avatar m1keil avatar mateumann avatar mxmrlv avatar nir0s avatar tehasdf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wagon's Issues

Add distro as an extra requirement

http://github.com/nir0s/distro is a new, more robust (and is now used by pip) implementation of Python's platform.linux_distribution() which will be removed in Python 3.7. We should first specify distro as an optional dependency for wagon (maybe allow to install it by running pip install wagon[dist]?) so that it can be used. We should keep using Python's implementation for now but deprecate it and then fully move to using distro (if still relevant) in Wagon v1.0.0

Change subcommand names to be consistent with `wheel`

Wheel's API provides the following:

  • wheel.archive
  • wheel.install
  • wheel.pkginfo
  • wheel.util

Maybe we should change the names of the subcommands to:

  • wagon archive (instead of create)
  • wagon pkginfo (instead of show)

WDYT?

Add Wagon version to metadata

To allow users to know which version of Wagon creates a specific wagon, we should provide it with each wagon's metadata. This will allow users to handle backward compatibility issues.

We can use:

import pkg_resources
wagon_version = pkg_resources.get_distribution('wagon').version

to get the version and then append it in the metadata: created_with: 'wagon-{0}'.format(version)

Don't refuse to install manylinux1_x86_64 wagons on x86_64

When building a wagon containing (e.g.) cffi, pip will happily pull down a manylinux1_x86_64 wheel. wagon will (sometimes; see #60) create a wagon with a supported platform of manylinux1_x86_64, but will then refuse to install this on a linux_x86_64 system, because the two strings don't match.

This is the output (note that I've opened #59 for the traceback):

+ wagon install -s foo-0.1.0-py27-none-manylinux1_x86_64-Ubuntu-precise.wgn
INFO - Installing foo-0.1.0-py27-none-manylinux1_x86_64-Ubuntu-precise.wgn
ERROR - Platform unsupported for package (linux_x86_64).
Traceback (most recent call last):
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/bin/wagon", line 11, in <module>
    sys.exit(main())
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/local/lib/python2.7/site-packages/click/core.py", line 716, in __call__
    return self.main(*args, **kwargs)
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/local/lib/python2.7/site-packages/click/core.py", line 696, in main
    rv = self.invoke(ctx)
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/local/lib/python2.7/site-packages/click/core.py", line 1060, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/local/lib/python2.7/site-packages/click/core.py", line 889, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/local/lib/python2.7/site-packages/click/core.py", line 534, in invoke
    return callback(*args, **kwargs)
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/local/lib/python2.7/site-packages/wagon/wagon.py", line 519, in install
    virtualenv, requirements_file, upgrade, ignore_platform, install_args)
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/local/lib/python2.7/site-packages/wagon/wagon.py", line 180, in install
    sys.exit(codes.errors['unsupported_platform_for_package'])
KeyError: 'unsupported_platform_for_package'

State in the docs that the API is unstable until v1.0.0

To accommodate for the inconsistencies between wagon and pip, and to allow for additional functionality, we will have to perform breaking changes until we can release v1.0.0. This should be stated in the docs so that people know they have to use specific versions of wagon to both create and install wagons.

supported_platform determination is unstable

With the advent of manylinux, a wagon can (validly) contain wheels for two platforms. In my case, the two platforms are linux_x86_64 and manylinux1_x86_64.

https://github.com/cloudify-cosmo/wagon/blob/master/wagon/utils.py#L241 assumes that the first non-any platform it finds applies to all wheels in the wagon, which means that a wagon containing exactly the same set of packages (some with linux_x86_64 and some with manylinux1_x86_64) can have a different supported_platform depending on the sort order of the directory containing the wheels.

when creating wagon with embedded python, it fails on missing venv env var.

DEBUG - installing to build/bdist.linux-x86_64/wheel
DEBUG - running install
DEBUG - Traceback (most recent call last):
DEBUG - File "", line 1, in
DEBUG - File "/tmp/pip-5nImSl-build/setup.py", line 82, in
DEBUG - 'cloudify-plugins-common>=3.4'
DEBUG - File "/opt/cfy/embedded/lib/python2.7/distutils/core.py", line 151, in setup
DEBUG - dist.run_commands()
DEBUG - File "/opt/cfy/embedded/lib/python2.7/distutils/dist.py", line 953, in run_commands
DEBUG - self.run_command(cmd)
DEBUG - File "/opt/cfy/embedded/lib/python2.7/distutils/dist.py", line 972, in run_command
DEBUG - cmd_obj.run()
DEBUG - File "/opt/cfy/embedded/lib/python2.7/site-packages/wheel/bdist_wheel.py", line 215, in run
DEBUG - self.run_command('install')
DEBUG - File "/opt/cfy/embedded/lib/python2.7/distutils/cmd.py", line 326, in run_command
DEBUG - self.distribution.run_command(command)
DEBUG - File "/opt/cfy/embedded/lib/python2.7/distutils/dist.py", line 972, in run_command
DEBUG - cmd_obj.run()
DEBUG - File "/tmp/pip-5nImSl-build/setup.py", line 68, in run
DEBUG - install_requirements()
DEBUG - File "/tmp/pip-5nImSl-build/setup.py", line 52, in install_requirements
DEBUG - pip_win_path = path.join(environ.get('VIRTUAL_ENV'), 'Scripts/pip.exe')
DEBUG - File "/opt/cfy/embedded/lib/python2.7/posixpath.py", line 77, in join
DEBUG - elif path == '' or path.endswith('/'):
DEBUG - AttributeError: 'NoneType' object has no attribute 'endswith'

Wagon should generate a zip archive by default

Currently, Wagon's default format when creating an archive is tar.gz on all platforms. This will make it harder to work with when using Windows. We should generate a zip by default to correspond with pip's implementation.

Make virtualenv an extra requirement

Virtualenv is currently a requirement because it is used in wagon validation but is not mandatory for creating and installing wagons.

Should we provide it as an extra requirement so that users can install it via pip install wagon['validate'] instead?

Remove requirement files abstraction

By passing the --with-requirements flag, we try to retrieve requirement files (namely, dev-requirements.txt and requirements.txt) automatically from a pip installable archive or a local directory. While this might be nice for the user, it's not explicit and might confuse users. It is also not consistent what pip and wheel which require explicitly passing the relevant requirement files via multiple -r flags.

I suggest we remove that and allow users to pass multiple -r flags with explicit paths (local or URLs) to requirement files.

Why not use plain "mega" wheels?

I wonder why you did not elect to create aggregated wheels instead which is a scenario that has been always support by wheel? (eg rewheeling several wheels in one single wheel?)

Wagon ignores output directory

When running wagon against a file system source project, it keeps trying to create the package in the current directory. For example, if the source project is in the current directory, it complains that the directory already exists. If I move to another directory (like /tmp, which is set as the output directory anyway) it works fine.

Wagon release 0.8.0 with pip >= 10 compatibility?

From the README:

If you're using pip>=10.x, please make sure you use wagon>=0.8.0

As far as I can tell, wagon 0.8.0 hasn't yet been published. Would it be possible to get a release so we can take the fix for #120 and start using wagon with pip >= 10.x?

Support `manylinux1` tag via auditwheel

While we can declare that wagon only supports manylinux1 if the wheels in it are manylinux1, I think we should add the ability to convert linux_x64_86 to manylinux1 to make the job a bit more comfortable for the user.

Relevant links:

Since auditwheel requires Centos 5 (not older) to work (due to forward backward compat of glibc), we can verify that version of the distribution and only if it's Centos 5-, allow to run wagon repair which will recursively repair all wheels in the wagon and recreate the wagon.

To test creating a manylinux1 compat wheel, try

$ docker run -i -t -v `pwd`:/io quay.io/pypa/manylinux1_x86_64 /bin/bash
$ /opt/python/cp35-cp35m/bin/pip wheel flask
$ auditwheel repair MarkupSafe-0.23-cp35-cp35m-linux_x86_64.whl
...

Repairing MarkupSafe-0.23-cp35-cp35m-linux_x86_64.whl
Previous filename tags: linux_x86_64
New filename tags: manylinux1_x86_64
Previous WHEEL info tags: cp35-cp35m-linux_x86_64
New WHEEL info tags: cp35-cp35m-manylinux1_x86_64

Fixed-up wheel written to /wheelhouse/MarkupSafe-0.23-cp35-cp35m-manylinux1_x86_64.whl
...

WDYT?

`wagon install` leaves a temporary directory behind

When performing an install with wagon 0.6.0, I see the following lines in the console output (with the app name replaced):

Extracting zip .../foo.wgn to /tmp/tmpWN6MLw...
Source is: /tmp/tmpWN6MLw/foo

Once installation is complete, /tmp/tmpWN6MLw still exists. This has caused a disk space issue for us in a Jenkins environment where we are installing wagons a lot.

Remove non-standard tag from wgn filename

Currently, Wagon appends two additional fields to each archive's file name if running on Linux - distribution name and distribution codename. These tags are not a part of the wheel standard and are only there to help with installing on Linux (if not all wheels are manylinux1).

To accommodate the need to still identify the Linux distribution and release the wagon was created on, these tags should be removed from the file name and remain in the metadata only (where they also currently reside). Once manylinux1 is (hopefully) easier to generate, we would be able to deprecate this information from the metadata as well.

Practically, this means that if you want to auto-identify on which distribution and release you most probably can install the wagon, you would have to either use the CLI or the API to retrieve its metadata and read the relevant fields.

Supported Python versions for an archive

Currently, the supported python versions are either provided via user input or automatically deduced (as a single version) from the python version currently used to create the wagon.

  1. We should rethink allowing users to provide the versions. It might be irrelevant
  2. We should redo the mechanism which understands the python versions supported as the current one is technically not true. We might want to iterate through all wheels and get the set of common versions and use them instead.

It should be possible to create a Wagon file for requirement files without source

I have a requirements file for a bunch of packages I want to install on some servers. I want to use Wagon to easily package and install them. However, Wagon forces me to select a "source" package. I can arbitrarily select one of the packages I want to install, specify it as "soruce", and remove it from the requirement files (to avoid a duplication error), but I think it would be best if I could just use Wagon to "archive" a list of unrelated packages.

Provide the relevant ABI tag for a wagon

Currently, wagon just assumes that the ABI if none. The ABI is wheel specific and so I'm not even sure there's a smart way to calculate it for multiple dependencies. WDYT? For now, it remains None, until we can figure out if we should at all address this issue.

Potential bug when importing virtualenv

We currently try to import virtualenv but also have many virtualenv variables in the code. We should probably change them to venv or something of that sort.

I've verified that the only place where we use the virtualenv module itself is where we check if it's found in globals. This should be changed to something like:

try:
    import virtualenv
    VIRTUALENV_EXISTS=True
except ImportError:
    VIRTUALENV_EXISTS=False

Wagons install in cloudify management 3.2

I went through the process of building "waggoned" plugins.

We are still using the 3.2 version of the Cloudify management server. It tries to pip install our Wagonned plugins, which fails, because there is no longer a setup.py file.

Is there any way to use wagons with cloudify 3.2?

Make the CLI's api consistent with regards to arbitrary pip/wheel args

Wagon's CLI's structure is not consistent with pip/wheel. For instance, providing a requirements file for wagon requires using the -a '-r requirements.txt' flag. Currently, this is not so important as the main idea by the -a flag is to allow users to pass any arguments to pip or wheel. At some point, we should make this API consistent.

pip 10.0.0 breaks wagon

pip 10 was released yesterday and is currently breaking Wagon. The --use-wheel flag was removed from pip and replaced by --only-binary.

Wagon fails to validate correct wagons

This is actually probably 2 issues.

Issue 1

Steps to reproduce:

  • wagon create pip
  • wagon validate <RESULTING_WAGON>
    The validation will fail.

Issue 2

The steps to reproduce are the same, but here the cause is clear - after pip install _s change to -s, and so this fails.
For example, here's a package on which create/validate will fail.

Logging by wagon should be more explicitly configurable

  1. The wagon logger logs is set to INFO level by default, perhaps this should be changed to DEBUG
  2. The functions exposed by the module have a verbose flag (which is just fine). Only problem is that this flag sets the logger logging level on each invocation. This may lead to unexpected behavior by users that may configure loggers in their app, etc...

Pip command not found with locally installed pip

(First, cool tool! Python needs something like a fat-jar equivalent from the java world)

If you look at _get_pip_path you can see it does not handle pip installs on machines that are:

  1. Not windows
  2. Not in a virtualenv
  3. Pip is not installed at /usr/bin/pip

https://github.com/cloudify-cosmo/wagon/blob/master/wagon.py#L448-L449

This happened for me because pip is installed here (default location by install from get-pip.py):

gnicholas$ which pip
/usr/local/bin/pip

Which results in the following when I try to create a package:

gnicholas$ wagon create . -r requirements.txt 
Creating archive for ....
Retrieving source...
Source is: .
setup.py file found. Retrieving name and version...
ae_deploy_utils
0.0.1
Downloading Wheels for ....
/bin/sh: /usr/bin/pip: No such file or directory
Failed to download wheels for: ['requirements.txt']

Possible fix?

You can invoke pip without knowing it's exact path using python's '-m' flag:
python -m "pip"

Remove the `-e` flag

We currently allow to install Wagon into a virtualenv directly by passing the -e VENV_PATH flag. This doesn't exist in pip, and so, for consistency's sake, we should remove it (specifically before Wagon v1.0.0).

Users can always activate a venv or directly pass its pip executable when installing a wagon.

Remove support for `excluded_packages`

The idea behind excluding packages was to allow users to install wagons in environments where some requirements were already installed (whether of the required dependency version or otherwise). Using constraint files, this feature isn't needed anymore and you can simply put a constraint on the already installed package in your environment.

Thus, the feature of excluding packages should be removed.

Release a wagon wheel to PyPI

This is only helpful for environments where pip (and therefore wheel) (and currently virtualenv - see #64) is installed as they can simply install Wagon's wheel via pip and don't require any additional dependencies. Funnily enough, if they don't have wheel they will need a wagon of wagon and need wagon to install it :)

Wagon 0.3.1 breaks creation and installation on Windows

Wagon 0.3.1 uses sys.executable as a reference to where pip is found. In Windows, that might not be in the sys.executable's path but rather under scripts. The tests are not broken since both Travis and Circle provide a build in version of Python where pip is available in the correct path.

We should provide special treatment for Windows.

wagon's invocation of `pip install` still tries to contact PyPI

This can be reproduced like this:

lxc launch ubuntu:x reproducer
lxc exec reproducer /bin/bash
apt update -y
apt install -y virtualenv
virtualenv -p $(which python3) venv
. venv/bin/activate
pip install git+https://github.com/cloudify-cosmo/wagon
wagon create Django
/etc/init.d/networking stop
wagon install Django-2.1.5-py27-none-any.wgn

This will eventually succeed, but takes a lot longer than normal because every individual package installation has lines like this:

Collecting Django
Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<pip._vendor.urllib3.connection.VerifiedHTTPSConnection object at 0x7f68eaca8b70>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution',)': /simple/django/
Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<pip._vendor.urllib3.connection.VerifiedHTTPSConnection object at 0x7f68eaca8898>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution',)': /simple/django/
Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<pip._vendor.urllib3.connection.VerifiedHTTPSConnection object at 0x7f68ead04f28>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution',)': /simple/django/
Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<pip._vendor.urllib3.connection.VerifiedHTTPSConnection object at 0x7f68ead04fd0>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution',)': /simple/django/
Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<pip._vendor.urllib3.connection.VerifiedHTTPSConnection object at 0x7f68eaca83c8>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution',)': /simple/django/

I've tracked this down: when wagon install calls pip, it does this:

/root/venv/bin/pip install Django --only-binary --no-index --find-links /tmp/tmpzLn8ik/Django/wheels --pre

However, --only-binary actually takes an argument, so it swallows the --no-index from the command-line, meaning that pip tries to contact PyPI.

(This may be related to #56, but I'm not seeing the same error output so I'm not sure.)

When using offline Wagon still tries to reach pypi.python.org

When using offline with a requirements.txt file and all packages found locally, with cmd wagon create -r -s my/folder/, Wagon still tries to reach for pypi.python.org to download wheels.
After about 2 minutes that it hangs it continues and create the wagon successfully.

"KeyError: 'unsupported_platform_for_package'" when installing a wagon on the wrong platform

+ wagon install -s foo-0.1.0-py27-none-manylinux1_x86_64-Ubuntu-precise.wgn
INFO - Installing foo-0.1.0-py27-none-manylinux1_x86_64-Ubuntu-precise.wgn
ERROR - Platform unsupported for package (linux_x86_64).
Traceback (most recent call last):
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/bin/wagon", line 11, in <module>
    sys.exit(main())
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/local/lib/python2.7/site-packages/click/core.py", line 716, in __call__
    return self.main(*args, **kwargs)
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/local/lib/python2.7/site-packages/click/core.py", line 696, in main
    rv = self.invoke(ctx)
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/local/lib/python2.7/site-packages/click/core.py", line 1060, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/local/lib/python2.7/site-packages/click/core.py", line 889, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/local/lib/python2.7/site-packages/click/core.py", line 534, in invoke
    return callback(*args, **kwargs)
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/local/lib/python2.7/site-packages/wagon/wagon.py", line 519, in install
    virtualenv, requirements_file, upgrade, ignore_platform, install_args)
  File "/srv/jenkins/jobs/TEMP-Wagon-Test/workspace/wagon_venv/local/lib/python2.7/site-packages/wagon/wagon.py", line 180, in install
    sys.exit(codes.errors['unsupported_platform_for_package'])
KeyError: 'unsupported_platform_for_package'

wagon searches system python for constrained dependencies when using embedded python

how to reproduce:
install a package with embedded python like:
https://gigaspaces-repository-eu.s3.amazonaws.com/org/cloudify3/3.4.0/m5/mgmt-worker-3.4.0~m5-394.el7.x86_64.rpm
create a constraints file: pip freeze > const.txt
download a wagon which has a dependency that exists in the constraints and doesn't exist in the system python like:
http://repository.cloudifysource.org/org/cloudify3/wagons/cloudify-diamond-plugin/1.3.2/cloudify_diamond_plugin-1.3.2-py27-none-linux_x86_64-centos-Core.wgn
install with prefix and constraint:
wagon install -s cloudify_diamond_plugin-1.3.2-py27-none-linux_x86_64-centos-Core.wgn -a '--prefix /opt/mgmtworker/env/plugins/cloudify-diamond-plugin-1.3.2 --constraint /opt/mgmtworker/env/const.txt --verbose'

one of the errors show usage of wrong pip:

Exception information:
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/pip/basecommand.py", line 209, in main
status = self.run(options, args)
File "/usr/lib/python2.7/site-packages/pip/commands/install.py", line 310, in run
wb.build(autobuilding=True)
File "/usr/lib/python2.7/site-packages/pip/wheel.py", line 748, in build
self.requirement_set.prepare_files(self.finder)
File "/usr/lib/python2.7/site-packages/pip/req/req_set.py", line 360, in prepare_files
ignore_dependencies=self.ignore_dependencies))
File "/usr/lib/python2.7/site-packages/pip/req/req_set.py", line 512, in _prepare_file
finder, self.upgrade, require_hashes)
File "/usr/lib/python2.7/site-packages/pip/req/req_install.py", line 273, in populate_link
self.link = finder.find_requirement(self, upgrade)
File "/usr/lib/python2.7/site-packages/pip/index.py", line 489, in find_requirement
'No matching distribution found for %s' % req
DistributionNotFound: No matching distribution found for cloudify-plugins-common==3.4a5 (from -c /opt/mgmtworker/env/const.txt (line 8))

Won't create wagon without virtualenv... while in a virtualenv

I have a virtualenv that's activated but that virtualenv does not have virtualenv installed (nor is it installed globally). Wagon fails due to a validation error that virtualenv is not available. I really can't imagine that this has an actual requirement (unless Wagon is creating its own virtualenv?!?) so I'm wondering why this is a fatal-error-level issue.

(venv) [gibson ~]$ wagon create -o ./wbuild --validate -v airflow
virtualenv is not installed and is required for the validation process. Please make sure virtualenv is installed and is in the path. (You can run 'pip install wagon[venv]')

(venv) [gibson ~]$ env | grep VIRTUAL_ENV
VIRTUAL_ENV=/home/ec2-user/venv

Maybe add uninstall command?

Allow an uninstall command to pip uninstall with dependencies. Since the metadata contains the entire set of the dependencies for the package, it can easily do that.

The caveat is that it might uninstall packages currently used in the same environment. Yuch.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.