Fixes line endings and adds some INFO and TODO comments

This commit is contained in:
Steve Dower 2016-02-09 08:26:49 -08:00
Родитель b2987d34b8
Коммит 4d75912f9e
13 изменённых файлов: 353 добавлений и 343 удалений

26
.gitattributes поставляемый
Просмотреть файл

@ -1,13 +1,13 @@
# Set the default behavior (used when a rule below doesn't match) # Set the default behavior (used when a rule below doesn't match)
* text=auto * text=auto
*.sln -text *.sln -text
*.ico -text *.ico -text
*.bmp -text *.bmp -text
*.png -text *.png -text
*.snk -text *.snk -text
*.mht -text *.mht -text
*.pickle -text *.pickle -text
# Some Windows-specific files should always be CRLF # Some Windows-specific files should always be CRLF
*.bat eol=crlf *.bat eol=crlf

122
.gitignore поставляемый
Просмотреть файл

@ -1,61 +1,61 @@
# Python cache # Python cache
__pycache__/ __pycache__/
*.pyc *.pyc
# Virtual environment # Virtual environment
env/ env/
# PTVS analysis # PTVS analysis
.ptvs/ .ptvs/
# Build results # Build results
bin/ bin/
obj/ obj/
dist/ dist/
MANIFEST MANIFEST
# Result of running python setup.py install/pip install -e # Result of running python setup.py install/pip install -e
RECORD.txt RECORD.txt
build/ build/
*.egg-info/ *.egg-info/
# Test results # Test results
TestResults/ TestResults/
# Credentials # Credentials
credentials_real.json credentials_real.json
testsettings_local.json testsettings_local.json
servicebus_settings_real.py servicebus_settings_real.py
storage_settings_real.py storage_settings_real.py
legacy_mgmt_settings_real.py legacy_mgmt_settings_real.py
mgmt_settings_real.py mgmt_settings_real.py
app_creds_real.py app_creds_real.py
# User-specific files # User-specific files
*.suo *.suo
*.user *.user
*.sln.docstates *.sln.docstates
.vs/ .vs/
# Windows image file caches # Windows image file caches
Thumbs.db Thumbs.db
ehthumbs.db ehthumbs.db
# Folder config file # Folder config file
Desktop.ini Desktop.ini
# Recycle Bin used on file shares # Recycle Bin used on file shares
$RECYCLE.BIN/ $RECYCLE.BIN/
# Mac desktop service store files # Mac desktop service store files
.DS_Store .DS_Store
.idea .idea
src/build src/build
*.iml *.iml
/doc/_build /doc/_build
/.vs/config/applicationhost.config /.vs/config/applicationhost.config
# Azure deployment credentials # Azure deployment credentials
*.pubxml *.pubxml

Просмотреть файл

@ -1 +1 @@
__import__('pkg_resources').declare_namespace(__name__) __import__('pkg_resources').declare_namespace(__name__)

Просмотреть файл

@ -1,4 +1,4 @@
import sys import sys
import azure.cli.main import azure.cli.main
sys.exit(azure.cli.main.main(sys.argv[1:])) sys.exit(azure.cli.main.main(sys.argv[1:]))

Просмотреть файл

@ -1,6 +1,6 @@
import argparse import argparse
class ArgumentParser(argparse.ArgumentParser): class ArgumentParser(argparse.ArgumentParser):
# TODO: Improve help appearance # TODO: Improve help appearance
pass pass

Просмотреть файл

@ -1,15 +1,20 @@
import os import os
try: try:
import configparser import configparser
except ImportError: except ImportError:
import ConfigParser as configparser import ConfigParser as configparser
_loaded_config = None _loaded_config = None
def get_config(): def get_config():
global _loaded_config '''Loads the user's azure.ini file and returns its contents.
if _loaded_config is None:
cfg = configparser.RawConfigParser() The file is only read once and the results cached. Modifications to
cfg.read(os.path.expanduser('~/azure.ini')) the file during execution will not be seen.
_loaded_config = cfg '''
return _loaded_config global _loaded_config
if _loaded_config is None:
cfg = configparser.RawConfigParser()
cfg.read(os.path.expanduser('~/azure.ini'))
_loaded_config = cfg
return _loaded_config

Просмотреть файл

@ -1,26 +1,26 @@
import logging import logging
# These arguments will be removed # These arguments will be removed
STRIP_ARGS = frozenset([ STRIP_ARGS = frozenset([
'-v', '-v',
'--verbose', '--verbose',
'--debug', '--debug',
]) ])
def configure_logging(argv): def configure_logging(argv):
# TODO: Configure logging handler to log messages to .py file # TODO: Configure logging handler to log messages to .py file
# Thinking here: # Thinking here:
# INFO messages as Python code # INFO messages as Python code
# DEBUG messages (if -v) as comments # DEBUG messages (if -v) as comments
# WARNING/ERROR messages as clearly marked comments # WARNING/ERROR messages as clearly marked comments
# Currently we just use the default format # Currently we just use the default format
level = logging.WARNING level = logging.WARNING
if '-v' in argv or '--verbose' in argv: if '-v' in argv or '--verbose' in argv:
level = logging.INFO level = logging.INFO
if '--debug' in argv: if '--debug' in argv:
level = logging.DEBUG level = logging.DEBUG
logging.basicConfig(level=level) logging.basicConfig(level=level)
return [a for a in argv if a not in STRIP_ARGS] return [a for a in argv if a not in STRIP_ARGS]

Просмотреть файл

@ -1,11 +1,11 @@
import logging import logging
import types import types
try: try:
from importlib import import_module from importlib import import_module
except ImportError: except ImportError:
def import_module(mod): def import_module(mod):
m = __import__(mod) m = __import__(mod)
for b in mod.split('.'): for b in mod.split('.'):
m = gettatr(m, b) m = gettatr(m, b)
return m return m

Просмотреть файл

@ -1,86 +1,86 @@
import logging import logging
from ..main import RC from ..main import RC
from .._util import import_module from .._util import import_module
COMMAND_MODULES = [ # TODO: Alternatively, simply scan the directory for all modules
'login', COMMAND_MODULES = [
'storage', 'login',
] 'storage',
]
MODULE_PREFIX = __package__ + '.'
MODULE_PREFIX = __package__ + '.'
def add_commands(top_level_parser):
from .._util import import_module def add_commands(top_level_parser):
for module in COMMAND_MODULES: for module in COMMAND_MODULES:
logging.debug("Adding commands from '%s'", module) logging.debug("Adding commands from '%s'", module)
mod = import_module(MODULE_PREFIX + module) mod = import_module(MODULE_PREFIX + module)
logging.debug(" - source: '%s'", mod.__file__) logging.debug(" - source: '%s'", mod.__file__)
parser = top_level_parser.add_parser(mod.COMMAND_NAME, help=mod.COMMAND_HELP) parser = top_level_parser.add_parser(mod.COMMAND_NAME, help=mod.COMMAND_HELP)
mod.add_commands(parser) mod.add_commands(parser)
valid = False valid = False
try: try:
mod.execute mod.execute
valid = True valid = True
except AttributeError: except AttributeError:
try: try:
mod.dispatch.execute mod.dispatch.execute
valid = True valid = True
except AttributeError: except AttributeError:
pass pass
assert valid, "Module {} has no 'execute()' or command dispatcher".format( assert valid, "Module {} has no 'execute()' or command dispatcher".format(
mod.__name__ mod.__name__
) )
def process_command(args): def process_command(args):
# service will be the azure.cli.commands.<service> module to import # service will be the azure.cli.commands.<service> module to import
service = (args.service or '').lower() service = (args.service or '').lower()
if not service: if not service:
raise RuntimeError(RC.UNKNOWN_SERVICE.format('')) raise RuntimeError(RC.UNKNOWN_SERVICE.format(''))
logging.debug("Importing '%s%s' for command", MODULE_PREFIX, service) logging.debug("Importing '%s%s' for command", MODULE_PREFIX, service)
try: try:
mod = import_module(MODULE_PREFIX + service) mod = import_module(MODULE_PREFIX + service)
except ImportError: except ImportError:
raise RuntimeError(RC.UNKNOWN_SERVICE.format(service)) raise RuntimeError(RC.UNKNOWN_SERVICE.format(service))
try: try:
execute = mod.execute execute = mod.execute
except AttributeError: except AttributeError:
execute = mod.dispatch.execute execute = mod.dispatch.execute
return execute(args) return execute(args)
class CommandDispatcher(object): class CommandDispatcher(object):
def __init__(self, command_name): def __init__(self, command_name):
self.command_name = command_name self.command_name = command_name
self.commands = {} self.commands = {}
def __call__(self, func_or_name): def __call__(self, func_or_name):
if isinstance(func_or_name, str): if isinstance(func_or_name, str):
def decorate(func): def decorate(func):
self.commands[func_or_name] = func self.commands[func_or_name] = func
return func return func
return decorate return decorate
self.commands[func_or_name.__name__] = func_or_name self.commands[func_or_name.__name__] = func_or_name
return func_or_name return func_or_name
def no_command(self): def no_command(self):
'''Displays a message when no command is available. '''Displays a message when no command is available.
Override this function with an argument parser's `print_help` Override this function with an argument parser's `print_help`
method to display help. method to display help.
''' '''
raise RuntimeError(RC.NO_COMMAND_GIVEN) raise RuntimeError(RC.NO_COMMAND_GIVEN)
def execute(self, args): def execute(self, args):
command = getattr(args, self.command_name, None) command = getattr(args, self.command_name, None)
if not command: if not command:
self.no_command() self.no_command()
return return
logging.debug("Dispatching to '%s'", command) logging.debug("Dispatching to '%s'", command)
return self.commands[command](args) return self.commands[command](args)

Просмотреть файл

@ -1,21 +1,22 @@
import logging import logging
from azure.cli.main import RC from azure.cli.main import RC
COMMAND_NAME = 'login' COMMAND_NAME = 'login'
COMMAND_HELP = 'helps you log in' COMMAND_HELP = RC.LOGIN_COMMAND_HELP
def add_commands(parser): def add_commands(parser):
parser.add_argument('--user', '-u', metavar=RC.USERNAME_METAVAR) parser.add_argument('--user', '-u', metavar=RC.USERNAME_METAVAR)
def execute(args): def execute(args):
'''Performs the 'login' command.''' user = args.user
if not user:
user = args.user # TODO: move string to RC
if not user: user = input('Enter username: ')
user = input('Enter username: ')
# INFO: Deliberately delay imports for startup performance
import getpass import getpass
password = getpass.getpass('Enter password for {}: '.format(user)) # TODO: move string to RC
password = getpass.getpass('Enter password for {}: '.format(user))
logging.info('''credentials = UserCredential({!r}, {!r})
'''.format(user, password)) logging.info('''credentials = UserCredential({!r}, {!r})
'''.format(user, password))

Просмотреть файл

@ -1,30 +1,34 @@
import logging import logging
from ..main import RC from ..main import RC
from ..commands import CommandDispatcher from ..commands import CommandDispatcher
COMMAND_NAME = RC.STORAGE_COMMAND COMMAND_NAME = 'storage'
COMMAND_HELP = RC.STORAGE_COMMAND_HELP COMMAND_HELP = RC.STORAGE_COMMAND_HELP
dispatch = CommandDispatcher('storage_command') dispatch = CommandDispatcher('storage_command')
def add_commands(parser): def add_commands(parser):
dispatch.no_command = parser.print_help dispatch.no_command = parser.print_help
commands = parser.add_subparsers(title=RC.COMMANDS, dest=dispatch.command_name) # INFO: Since "storage" has subcommands, we need to add subparsers
# Each subcommand is added to `commands` using `add_parser`
cna = commands.add_parser('checkname', help="check the availability of an account name") commands = parser.add_subparsers(title=RC.COMMANDS, dest=dispatch.command_name)
cna.add_argument('--account_name', '-a', type=str, metavar=RC.NAME_METAVAR, required=True)
# TODO: move help string to RC
@dispatch cna = commands.add_parser('checkname', help="check the availability of an account name")
def checkname(args): cna.add_argument('--account_name', '-a', type=str, metavar=RC.NAME_METAVAR, required=True)
'''Performs the 'checkname' command'''
from azure.mgmt.storage import StorageManagementClient, StorageManagementClientConfiguration # INFO: Applying @dispatch enables the processor to call directly into this function
# If the function name does not match the command, use @dispatch("command")
logging.info('''smc = StorageManagementClient(StorageManagementClientConfiguration()) @dispatch
smc.storage_accounts.check_name_availability({account_name!r}) def checkname(args):
'''.format_map(vars(args))) from azure.mgmt.storage import StorageManagementClient, StorageManagementClientConfiguration
smc = StorageManagementClient(StorageManagementClientConfiguration()) logging.info('''smc = StorageManagementClient(StorageManagementClientConfiguration())
logging.warn(smc.storage_accounts.check_name_availability(args.account_name)) smc.storage_accounts.check_name_availability({account_name!r})
'''.format_map(vars(args)))
smc = StorageManagementClient(StorageManagementClientConfiguration())
logging.warn(smc.storage_accounts.check_name_availability(args.account_name))

Просмотреть файл

@ -1,50 +1,50 @@
import logging import logging
from ._argparse import ArgumentParser from ._argparse import ArgumentParser
from ._logging import configure_logging from ._logging import configure_logging
from ._util import import_module from ._util import import_module
__author__ = "Microsoft Corporation <python@microsoft.com>" __author__ = "Microsoft Corporation <python@microsoft.com>"
__version__ = "2016.2.4" __version__ = "2016.2.4"
# TODO: detect language and load correct resources # TODO: detect language and load correct resources
RC = import_module('azure.cli.resources-en_US') RC = import_module('azure.cli.resources-en_US')
def main(argv): def main(argv):
# configure_logging will remove any arguments it uses so we do not # configure_logging will remove any arguments it uses so we do not
# need to worry about parsing them elsewhere # need to worry about parsing them elsewhere
argv = configure_logging(argv) argv = configure_logging(argv)
parser = ArgumentParser( parser = ArgumentParser(
prog=RC.PROG, prog=RC.PROG,
description=RC.DESCRIPTION, description=RC.DESCRIPTION,
fromfile_prefix_chars='@', fromfile_prefix_chars='@',
) )
parser.add_argument('--api-version', help=RC.API_VERSION_HELP) parser.add_argument('--api-version', help=RC.API_VERSION_HELP)
services = parser.add_subparsers( services = parser.add_subparsers(
title=RC.SERVICES, title=RC.SERVICES,
help=RC.SERVICES_HELP, help=RC.SERVICES_HELP,
dest='service', dest='service',
) )
from .commands import add_commands, process_command from .commands import add_commands, process_command
callbacks = add_commands(services) callbacks = add_commands(services)
args = parser.parse_args(argv) args = parser.parse_args(argv)
if not args.service: if not args.service:
parser.print_help() parser.print_help()
return 1 return 1
if args.api_version: if args.api_version:
logging.debug('Using api version %s', args.api_version) logging.debug('Using api version %s', args.api_version)
# TODO: Force use of specified version # TODO: Force use of specified version
# Probably by extending azure.__path__ to load the correct version of azure.mgmt # Probably by extending azure.__path__ to load the correct version of azure.mgmt
pass pass
try: try:
process_command(args) process_command(args)
except RuntimeError as ex: except RuntimeError as ex:
logging.error(ex.args[0]) logging.error(ex.args[0])
return ex.args[1] if len(ex.args) >= 2 else -1 return ex.args[1] if len(ex.args) >= 2 else -1

Просмотреть файл

@ -1,20 +1,20 @@
PROG = 'azure' PROG = 'azure'
DESCRIPTION = "Azure Command-Line Tools" DESCRIPTION = "Azure Command-Line Tools"
API_VERSION_HELP = "specify the API version set to use (yyyy-mm-dd)" API_VERSION_HELP = "specify the API version set to use (yyyy-mm-dd)"
SERVICES = "services" SERVICES = "services"
SERVICES_HELP = "select the service" SERVICES_HELP = "select the service"
COMMANDS = "commands" COMMANDS = "commands"
UNKNOWN_SERVICE = "unrecognized service '{0}'" UNKNOWN_SERVICE = "unrecognized service '{0}'"
UNKNOWN_COMMAND = "{0} service does not support command '{1}'" UNKNOWN_COMMAND = "{0} service does not support command '{1}'"
NO_COMMAND_GIVEN = "no command specified" NO_COMMAND_GIVEN = "no command specified"
STORAGE_COMMAND = "storage" STORAGE_COMMAND_HELP = "provides storage operations"
STORAGE_COMMAND_HELP = "provides storage operations" LOGIN_COMMAND_HELP = "helps you log in"
USERNAME_METAVAR = '<username>' USERNAME_METAVAR = '<username>'
NAME_METAVAR = '<name>' NAME_METAVAR = '<name>'