diff --git a/azure-mgmt-compute/README.rst b/azure-mgmt-compute/README.rst index 69f82209c777..cc57dfa74240 100644 --- a/azure-mgmt-compute/README.rst +++ b/azure-mgmt-compute/README.rst @@ -6,7 +6,7 @@ This is the Microsoft Azure Compute Management Client Library. Azure Resource Manager (ARM) is the next generation of management APIs that replace the old Azure Service Management (ASM). -This package has been tested with Python 2.7, 3.3, 3.4, 3.5 and 3.6. +This package has been tested with Python 2.7, 3.4, 3.5 and 3.6. For the older Azure Service Management (ASM) libraries, see `azure-servicemanagement-legacy `__ library. @@ -36,7 +36,7 @@ If you see azure==0.11.0 (or any version below 1.0), uninstall it first: Usage ===== -For code examples, see `Compute and Network Resource Management +For code examples, see `Compute Management `__ on docs.microsoft.com. diff --git a/azure-mgmt-compute/sdk_packaging.toml b/azure-mgmt-compute/sdk_packaging.toml new file mode 100644 index 000000000000..447ccf936dbe --- /dev/null +++ b/azure-mgmt-compute/sdk_packaging.toml @@ -0,0 +1,5 @@ +[packaging] +package_name = "azure-mgmt-compute" +package_pprint_name = "Compute Management" +package_doc_id = "virtualmachines" +is_stable = true diff --git a/azure-mgmt-compute/setup.py b/azure-mgmt-compute/setup.py index 4f04a54f68ff..bf45210b4e22 100644 --- a/azure-mgmt-compute/setup.py +++ b/azure-mgmt-compute/setup.py @@ -77,7 +77,7 @@ zip_safe=False, packages=find_packages(exclude=["tests"]), install_requires=[ - 'msrestazure>=0.4.20,<2.0.0', + 'msrestazure>=0.4.27,<2.0.0', 'azure-common~=1.1', ], cmdclass=cmdclass diff --git a/azure-mgmt-scheduler/sdk_packaging.toml b/azure-mgmt-scheduler/sdk_packaging.toml new file mode 100644 index 000000000000..67fca4a18ae9 --- /dev/null +++ b/azure-mgmt-scheduler/sdk_packaging.toml @@ -0,0 +1,6 @@ +[packaging] +package_name = "azure-mgmt-scheduler" +package_pprint_name = "Scheduler Management" +package_doc_id = "scheduler" +is_stable = true + diff --git a/azure-sdk-testutils/devtools_testutils/__init__.py b/azure-sdk-tools/devtools_testutils/__init__.py similarity index 100% rename from azure-sdk-testutils/devtools_testutils/__init__.py rename to azure-sdk-tools/devtools_testutils/__init__.py diff --git a/azure-sdk-testutils/devtools_testutils/config.py b/azure-sdk-tools/devtools_testutils/config.py similarity index 100% rename from azure-sdk-testutils/devtools_testutils/config.py rename to azure-sdk-tools/devtools_testutils/config.py diff --git a/azure-sdk-testutils/devtools_testutils/mgmt_settings_fake.py b/azure-sdk-tools/devtools_testutils/mgmt_settings_fake.py similarity index 100% rename from azure-sdk-testutils/devtools_testutils/mgmt_settings_fake.py rename to azure-sdk-tools/devtools_testutils/mgmt_settings_fake.py diff --git a/azure-sdk-testutils/devtools_testutils/mgmt_testcase.py b/azure-sdk-tools/devtools_testutils/mgmt_testcase.py similarity index 100% rename from azure-sdk-testutils/devtools_testutils/mgmt_testcase.py rename to azure-sdk-tools/devtools_testutils/mgmt_testcase.py diff --git a/azure-sdk-testutils/devtools_testutils/resource_testcase.py b/azure-sdk-tools/devtools_testutils/resource_testcase.py similarity index 100% rename from azure-sdk-testutils/devtools_testutils/resource_testcase.py rename to azure-sdk-tools/devtools_testutils/resource_testcase.py diff --git a/azure-sdk-testutils/devtools_testutils/setup.py b/azure-sdk-tools/devtools_testutils/setup.py similarity index 100% rename from azure-sdk-testutils/devtools_testutils/setup.py rename to azure-sdk-tools/devtools_testutils/setup.py diff --git a/azure-sdk-testutils/devtools_testutils/storage_testcase.py b/azure-sdk-tools/devtools_testutils/storage_testcase.py similarity index 100% rename from azure-sdk-testutils/devtools_testutils/storage_testcase.py rename to azure-sdk-tools/devtools_testutils/storage_testcase.py diff --git a/scripts/packaging_requirements.txt b/azure-sdk-tools/packaging_requirements.txt similarity index 55% rename from scripts/packaging_requirements.txt rename to azure-sdk-tools/packaging_requirements.txt index 87db124f67a4..d9a11ca2377a 100644 --- a/scripts/packaging_requirements.txt +++ b/azure-sdk-tools/packaging_requirements.txt @@ -1,3 +1,4 @@ -cookiecutter packaging wheel +Jinja2 +pytoml \ No newline at end of file diff --git a/azure-sdk-tools/packaging_tools/__init__.py b/azure-sdk-tools/packaging_tools/__init__.py new file mode 100644 index 000000000000..ab7099952f52 --- /dev/null +++ b/azure-sdk-tools/packaging_tools/__init__.py @@ -0,0 +1,62 @@ +import logging +from pathlib import Path +from typing import Dict, Any + +from jinja2 import Template, PackageLoader, Environment +from .conf import read_conf, build_default_conf, CONF_NAME + +_LOGGER = logging.getLogger(__name__) + +_CWD = Path(__file__).resolve().parent +_TEMPLATE_PATH = _CWD / "template" + +def build_config(config : Dict[str, Any]) -> Dict[str, str]: + """Will build the actual config for Jinja2, based on SDK config. + """ + result = config.copy() + # Manage the classifier stable/beta + is_stable = result.pop("is_stable", False) + if is_stable: + result["classifier"] = "Development Status :: 5 - Production/Stable" + else: + result["classifier"] = "Development Status :: 4 - Beta" + # Manage the nspkg + package_name = result["package_name"] + result["package_nspkg"] = package_name[:package_name.rindex('-')]+"-nspkg" + + # Return result + return result + +def build_packaging(package_name: str, output_folder: str, build_conf: bool = False) -> None: + _LOGGER.info("Building template %s", package_name) + package_folder = Path(output_folder) / Path(package_name) + + if build_conf: + build_default_conf(package_folder, package_name) + + conf = read_conf(package_folder) + if not conf: + raise ValueError("Create a {} file before calling this script".format(package_folder / CONF_NAME)) + + env = Environment( + loader=PackageLoader('packaging_tools', 'templates'), + keep_trailing_newline=True + ) + conf = build_config(conf) + + for template_name in env.list_templates(): + future_filepath = Path(output_folder) / package_name / template_name + + # Might decide to make it more generic one day + if template_name == "HISTORY.rst" and future_filepath.exists(): + _LOGGER.info("Skipping HISTORY.txt template, since a previous one was found") + # Never overwirte the ChangeLog + continue + + template = env.get_template(template_name) + result = template.render(**conf) + + with open(Path(output_folder) / package_name / template_name, "w") as fd: + fd.write(result) + + _LOGGER.info("Template done %s", package_name) \ No newline at end of file diff --git a/azure-sdk-tools/packaging_tools/__main__.py b/azure-sdk-tools/packaging_tools/__main__.py new file mode 100644 index 000000000000..2faec6d52012 --- /dev/null +++ b/azure-sdk-tools/packaging_tools/__main__.py @@ -0,0 +1,41 @@ +import argparse +import logging +import sys + +from . import build_packaging + +_LOGGER = logging.getLogger(__name__) + +_epilog="""This script will automatically build the TOML configuration file with default value if it doesn't exist. +""" + +parser = argparse.ArgumentParser( + description='Packaging tools for Azure SDK for Python', + formatter_class=argparse.RawTextHelpFormatter, + epilog=_epilog +) +parser.add_argument('--output', '-o', + dest='output', default='.', + help='Output dir, should be SDK repo folder. [default: %(default)s]') +parser.add_argument("--debug", + dest="debug", action="store_true", + help="Verbosity in DEBUG mode") +parser.add_argument("--build-conf", + dest="build_conf", action="store_true", + help="Build a default TOML file, with package name, fake pretty name, as beta package and no doc page. Do nothing if the file exists, remove manually the file if needed.") +parser.add_argument('package_name', help='The package name.') + +args = parser.parse_args() + +main_logger = logging.getLogger() +logging.basicConfig() +main_logger.setLevel(logging.DEBUG if args.debug else logging.INFO) + +try: + build_packaging(args.package_name, args.output, build_conf=args.build_conf) +except Exception as err: + if args.debug: + _LOGGER.exception(err) + else: + _LOGGER.critical(err) + sys.exit(1) \ No newline at end of file diff --git a/azure-sdk-tools/packaging_tools/conf.py b/azure-sdk-tools/packaging_tools/conf.py new file mode 100644 index 000000000000..6140b6eac2de --- /dev/null +++ b/azure-sdk-tools/packaging_tools/conf.py @@ -0,0 +1,39 @@ +import logging +from pathlib import Path +from typing import Dict, Any + +import pytoml as toml + +_LOGGER = logging.getLogger(__name__) + +CONF_NAME = "sdk_packaging.toml" +_SECTION = "packaging" + +# Default conf +_CONFIG = { + "package_name": "packagename", + "package_pprint_name": "MyService Management", + "package_doc_id": "", + "is_stable": False +} + +def read_conf(folder: Path) -> Dict[str, Any]: + conf_path = folder / CONF_NAME + if not conf_path.exists(): + return {} + + with open(conf_path, "rb") as fd: + return toml.load(fd)[_SECTION] + +def build_default_conf(folder: Path, package_name: str) -> None: + conf_path = folder / CONF_NAME + if conf_path.exists(): + _LOGGER.info("Skipping default conf since the file exists") + return + + _LOGGER.info("Build default conf for %s", package_name) + conf = {_SECTION: _CONFIG.copy()} + conf[_SECTION]["package_name"] = package_name + + with open(conf_path, "w") as fd: + toml.dump(conf, fd) diff --git a/azure-sdk-tools/packaging_tools/templates/HISTORY.rst b/azure-sdk-tools/packaging_tools/templates/HISTORY.rst new file mode 100644 index 000000000000..8924d5d6c445 --- /dev/null +++ b/azure-sdk-tools/packaging_tools/templates/HISTORY.rst @@ -0,0 +1,9 @@ +.. :changelog: + +Release History +=============== + +0.1.0 (1970-01-01) +++++++++++++++++++ + +* Initial Release diff --git a/azure-sdk-tools/packaging_tools/templates/MANIFEST.in b/azure-sdk-tools/packaging_tools/templates/MANIFEST.in new file mode 100644 index 000000000000..9ecaeb15de50 --- /dev/null +++ b/azure-sdk-tools/packaging_tools/templates/MANIFEST.in @@ -0,0 +1,2 @@ +include *.rst +include azure_bdist_wheel.py \ No newline at end of file diff --git a/azure-sdk-tools/packaging_tools/templates/README.rst b/azure-sdk-tools/packaging_tools/templates/README.rst new file mode 100644 index 000000000000..41025dfbb229 --- /dev/null +++ b/azure-sdk-tools/packaging_tools/templates/README.rst @@ -0,0 +1,49 @@ +Microsoft Azure SDK for Python +============================== + +This is the Microsoft Azure {{package_pprint_name}} Client Library. + +Azure Resource Manager (ARM) is the next generation of management APIs that +replace the old Azure Service Management (ASM). + +This package has been tested with Python 2.7, 3.4, 3.5 and 3.6. + +For the older Azure Service Management (ASM) libraries, see +`azure-servicemanagement-legacy `__ library. + +For a more complete set of Azure libraries, see the `azure `__ bundle package. + + +Compatibility +============= + +**IMPORTANT**: If you have an earlier version of the azure package +(version < 1.0), you should uninstall it before installing this package. + +You can check the version using pip: + +.. code:: shell + + pip freeze + +If you see azure==0.11.0 (or any version below 1.0), uninstall it first: + +.. code:: shell + + pip uninstall azure + + +Usage +===== + +For code examples, see `{{package_pprint_name}} +`__ +on docs.microsoft.com. + + +Provide Feedback +================ + +If you encounter any bugs or have suggestions, please file an issue in the +`Issues `__ +section of the project. diff --git a/azure-sdk-tools/packaging_tools/templates/azure_bdist_wheel.py b/azure-sdk-tools/packaging_tools/templates/azure_bdist_wheel.py new file mode 100644 index 000000000000..8a81d1b61775 --- /dev/null +++ b/azure-sdk-tools/packaging_tools/templates/azure_bdist_wheel.py @@ -0,0 +1,54 @@ +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +#-------------------------------------------------------------------------- + +from distutils import log as logger +import os.path + +from wheel.bdist_wheel import bdist_wheel +class azure_bdist_wheel(bdist_wheel): + """The purpose of this class is to build wheel a little differently than the sdist, + without requiring to build the wheel from the sdist (i.e. you can build the wheel + directly from source). + """ + + description = "Create an Azure wheel distribution" + + user_options = bdist_wheel.user_options + \ + [('azure-namespace-package=', None, + "Name of the deepest nspkg used")] + + def initialize_options(self): + bdist_wheel.initialize_options(self) + self.azure_namespace_package = None + + def finalize_options(self): + bdist_wheel.finalize_options(self) + if self.azure_namespace_package and not self.azure_namespace_package.endswith("-nspkg"): + raise ValueError("azure_namespace_package must finish by -nspkg") + + def run(self): + if not self.distribution.install_requires: + self.distribution.install_requires = [] + self.distribution.install_requires.append( + "{}>=2.0.0".format(self.azure_namespace_package)) + bdist_wheel.run(self) + + def write_record(self, bdist_dir, distinfo_dir): + if self.azure_namespace_package: + # Split and remove last part, assuming it's "nspkg" + subparts = self.azure_namespace_package.split('-')[0:-1] + folder_with_init = [os.path.join(*subparts[0:i+1]) for i in range(len(subparts))] + for azure_sub_package in folder_with_init: + init_file = os.path.join(bdist_dir, azure_sub_package, '__init__.py') + if os.path.isfile(init_file): + logger.info("manually remove {} while building the wheel".format(init_file)) + os.remove(init_file) + else: + raise ValueError("Unable to find {}. Are you sure of your namespace package?".format(init_file)) + bdist_wheel.write_record(self, bdist_dir, distinfo_dir) +cmdclass = { + 'bdist_wheel': azure_bdist_wheel, +} diff --git a/azure-sdk-tools/packaging_tools/templates/setup.cfg b/azure-sdk-tools/packaging_tools/templates/setup.cfg new file mode 100644 index 000000000000..57c8683c0b05 --- /dev/null +++ b/azure-sdk-tools/packaging_tools/templates/setup.cfg @@ -0,0 +1,3 @@ +[bdist_wheel] +universal=1 +azure-namespace-package={{package_nspkg}} \ No newline at end of file diff --git a/azure-sdk-tools/packaging_tools/templates/setup.py b/azure-sdk-tools/packaging_tools/templates/setup.py new file mode 100644 index 000000000000..584d888a218e --- /dev/null +++ b/azure-sdk-tools/packaging_tools/templates/setup.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python + +#------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +#-------------------------------------------------------------------------- + +import re +import os.path +from io import open +from setuptools import find_packages, setup +try: + from azure_bdist_wheel import cmdclass +except ImportError: + from distutils import log as logger + logger.warn("Wheel is not available, disabling bdist_wheel hook") + cmdclass = {} + +# Change the PACKAGE_NAME only to change folder and different name +PACKAGE_NAME = "{{package_name}}" +PACKAGE_PPRINT_NAME = "{{package_pprint_name}}" + +# a-b-c => a/b/c +package_folder_path = PACKAGE_NAME.replace('-', '/') +# a-b-c => a.b.c +namespace_name = PACKAGE_NAME.replace('-', '.') + +# azure v0.x is not compatible with this package +# azure v0.x used to have a __version__ attribute (newer versions don't) +try: + import azure + try: + ver = azure.__version__ + raise Exception( + 'This package is incompatible with azure=={}. '.format(ver) + + 'Uninstall it with "pip uninstall azure".' + ) + except AttributeError: + pass +except ImportError: + pass + +# Version extraction inspired from 'requests' +with open(os.path.join(package_folder_path, 'version.py'), 'r') as fd: + version = re.search(r'^VERSION\s*=\s*[\'"]([^\'"]*)[\'"]', + fd.read(), re.MULTILINE).group(1) + +if not version: + raise RuntimeError('Cannot find version information') + +with open('README.rst', encoding='utf-8') as f: + readme = f.read() +with open('HISTORY.rst', encoding='utf-8') as f: + history = f.read() + +setup( + name=PACKAGE_NAME, + version=version, + description='Microsoft Azure {} Client Library for Python'.format(PACKAGE_PPRINT_NAME), + long_description=readme + '\n\n' + history, + license='MIT License', + author='Microsoft Corporation', + author_email='azpysdkhelp@microsoft.com', + url='https://github.com/Azure/azure-sdk-for-python', + classifiers=[ + '{{classifier}}', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'License :: OSI Approved :: MIT License', + ], + zip_safe=False, + packages=find_packages(exclude=["tests"]), + install_requires=[ + 'msrestazure>=0.4.27,<2.0.0', + 'azure-common~=1.1', + ], + cmdclass=cmdclass +) diff --git a/azure-sdk-testutils/setup.py b/azure-sdk-tools/setup.py similarity index 84% rename from azure-sdk-testutils/setup.py rename to azure-sdk-tools/setup.py index c5832f90bee2..77df62008bc6 100644 --- a/azure-sdk-testutils/setup.py +++ b/azure-sdk-tools/setup.py @@ -5,9 +5,9 @@ # locally with "pip install -e" setup( - name = "azure-sdk-testutils", + name = "azure-sdk-tools", version = "0.0.0", - author='Microsoft Corporation', + author='Microsoft Corporation', author_email='azpysdkhelp@microsoft.com', url='https://github.com/Azure/azure-sdk-for-python', packages=find_packages(), diff --git a/azure-sdk-testutils/test-requirements.txt b/azure-sdk-tools/test-requirements.txt similarity index 100% rename from azure-sdk-testutils/test-requirements.txt rename to azure-sdk-tools/test-requirements.txt diff --git a/scripts/dev_setup.py b/scripts/dev_setup.py index 66de1f42309d..8441539d861a 100644 --- a/scripts/dev_setup.py +++ b/scripts/dev_setup.py @@ -50,10 +50,10 @@ def pip_command(command): pip_command('install -e {}'.format(package_name)) # install test requirements -pip_command('install -r azure-sdk-testutils/test-requirements.txt') +pip_command('install -r azure-sdk-tools/test-requirements.txt') # install packaging requirements -pip_command('install -r scripts/packaging_requirements.txt') +pip_command('install -r azure-sdk-tools/packaging_requirements.txt') # Ensure that the site package's azure/__init__.py has the old style namespace # package declaration by installing the old namespace package