Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

help infrastructure #68

Closed
wants to merge 22 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
initial version, changing direction
BurtBiel committed Mar 15, 2016
commit 6c9bbb0cf4790a46ec9305e4f30e28af17903ed8
51 changes: 50 additions & 1 deletion azure-cli.pyproj
Original file line number Diff line number Diff line change
@@ -12,8 +12,10 @@
<OutputPath>.</OutputPath>
<ProjectTypeGuids>{888888a0-9f3d-457c-b088-3a5042f75d52}</ProjectTypeGuids>
<LaunchProvider>Standard Python launcher</LaunchProvider>
<InterpreterId>{1dd9c42b-5980-42ce-a2c3-46d3bf0eede4}</InterpreterId>
<InterpreterId>{12627503-1b89-4332-94a5-8ddd298e66ac}</InterpreterId>
<InterpreterVersion>3.5</InterpreterVersion>
<CommandLineArguments>login --help</CommandLineArguments>
<EnableNativeCodeDebugging>False</EnableNativeCodeDebugging>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'" />
<PropertyGroup Condition="'$(Configuration)' == 'Release'" />
@@ -40,6 +42,9 @@
<Compile Include="azure\cli\tests\test_connection_verify.py" />
<Compile Include="azure\cli\tests\test_output.py" />
<Compile Include="azure\cli\_debug.py" />
<Compile Include="azure\cli\_help.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="azure\cli\_locale.py" />
<Compile Include="azure\cli\tests\test_profile.py" />
<Compile Include="azure\cli\_argparse.py" />
@@ -64,6 +69,50 @@
<Folder Include="azure\cli\tests\" />
</ItemGroup>
<ItemGroup>
<Interpreter Include="..\..\Temp\burt\env27AppInsights\">
<Id>{153669af-0334-46c7-a6f1-029c48dc84d1}</Id>
<BaseInterpreter>{2af0f10d-7135-4994-9156-5d01c9c11b7e}</BaseInterpreter>
<Version>2.7</Version>
<Description>env27AppInsights (Python 2.7)</Description>
<InterpreterPath>Scripts\python.exe</InterpreterPath>
<WindowsInterpreterPath>Scripts\pythonw.exe</WindowsInterpreterPath>
<LibraryPath>Lib\</LibraryPath>
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
<Architecture>X86</Architecture>
</Interpreter>
<Interpreter Include="..\..\Temp\burt\env27b\">
<Id>{83c20e12-84e3-4c10-a1ba-466d2b57483d}</Id>
<BaseInterpreter>{2af0f10d-7135-4994-9156-5d01c9c11b7e}</BaseInterpreter>
<Version>2.7</Version>
<Description>env27b (Python 2.7)</Description>
<InterpreterPath>Scripts\python.exe</InterpreterPath>
<WindowsInterpreterPath>Scripts\pythonw.exe</WindowsInterpreterPath>
<LibraryPath>Lib\</LibraryPath>
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
<Architecture>X86</Architecture>
</Interpreter>
<Interpreter Include="..\..\Temp\burt\env35AppInsights\">
<Id>{12627503-1b89-4332-94a5-8ddd298e66ac}</Id>
<BaseInterpreter>{2af0f10d-7135-4994-9156-5d01c9c11b7e}</BaseInterpreter>
<Version>3.5</Version>
<Description>env35AppInsights (Python 3.5)</Description>
<InterpreterPath>Scripts\python.exe</InterpreterPath>
<WindowsInterpreterPath>Scripts\pythonw.exe</WindowsInterpreterPath>
<LibraryPath>Lib\</LibraryPath>
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
<Architecture>X86</Architecture>
</Interpreter>
<Interpreter Include="..\..\Temp\burt\env35d\">
<Id>{4ae3497d-f45c-4ec2-9e26-57476ef276a0}</Id>
<BaseInterpreter>{2af0f10d-7135-4994-9156-5d01c9c11b7e}</BaseInterpreter>
<Version>3.5</Version>
<Description>env35d (Python 3.5)</Description>
<InterpreterPath>Scripts\python.exe</InterpreterPath>
<WindowsInterpreterPath>Scripts\pythonw.exe</WindowsInterpreterPath>
<LibraryPath>Lib\</LibraryPath>
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
<Architecture>X86</Architecture>
</Interpreter>
<Interpreter Include="..\env\">
<Id>{1dd9c42b-5980-42ce-a2c3-46d3bf0eede4}</Id>
<BaseInterpreter>{2af0f10d-7135-4994-9156-5d01c9c11b7e}</BaseInterpreter>
6 changes: 6 additions & 0 deletions src/azure/cli/_argparse.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import print_function
import sys

from ._help import HelpFile, print_detailed_help
from ._locale import L, get_file as locale_get_file
from ._logging import logger
from ._output import OutputProducer
@@ -249,6 +250,11 @@ def not_global(a):
sys.stdout = old_stdout

def _display_usage(self, nouns, noun_map, out=sys.stdout):
doc = HelpFile(noun_map['$doc'][:-4])
if doc:
print_detailed_help(doc)
return

spec = ' '.join(noun_map.get('$spec') or nouns)
print(' {} {}'.format(self.prog, spec), file=out)
print(file=out)
141 changes: 141 additions & 0 deletions src/azure/cli/_help.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import sys
import textwrap
from collections import OrderedDict

from yaml import load, dump

from ._output import OutputProducer, TableOutput, format_table, format_list, format_unordered_list

def print_detailed_help(help_file, out=sys.stdout): # TODO: wire up out to print statements
indent = 0
print('')
_printIndent('{0}: {1}'.format(help_file.command, help_file.short_summary), indent)

indent = 1
_printIndent('{0}'.format(help_file.long_summary), indent)
print('')

indent = 0
_printIndent('Arguments', indent)

if help_file.type == 'command':
for p in help_file.parameters:
indent = 1
_printIndent('{0}: {1}'.format(p.name, p.short_summary), indent)

indent = 2
_printIndent('{0}'.format(p.long_summary), indent)

if p.value_sources:
_printIndent("Values from: {0}".format(', '.join(p.value_sources)), indent)
print('')

if help_file.type == 'group':
indent = 1
for c in help_file.children:
_printIndent('{0}: {1}'.format(c.name, c.short_summary), indent)


class HelpFile(object):
def __init__(self, delimiters):
self._delimiters = delimiters
self._data = {}

@property
def name(self):
return self._delimiters.split('.')[-1]

@property
def command(self):
return self._delimiters.replace('.', ' ')

@property
def type(self):
t = self._data.get('type')
if t != 'command' and t != 'group':
raise HelpAuthoringException('help file type must be "command" or "group"')
return t

@property
def short_summary(self):
return self._data.get('short-summary')

@property
def long_summary(self):
return self._data.get('long-summary')

@property
def parameters(self):
return [HelpParameter(x) for x in self._data.get('parameters')]

@property
def children(self):
return [HelpFile(d) for d in _load_child_delimiters(self._delimiters)]

def load_saved_data(self):
self._data = _load_help_file(delimiters)

class HelpParameter(object):
def __init__(self, _data):
self._data = _data

@property
def name(self):
return self._data.get('name')

@property
def required(self):
return bool(self._data.get('required'))

@property
def short_summary(self):
return self._data.get('short-summary')

@property
def long_summary(self):
return self._data.get('long-summary')

@property
def type(self):
return self._data.get('type')

@property
def value_sources(self):
return self._data.get('populator-commands')


def _printIndent(str, indent=0):
tw = textwrap.TextWrapper(initial_indent = " "*indent, subsequent_indent = " "*indent)
print(tw.fill(str))

def _load_help_file(delimiters):
s = """
type: command
short-summary: this module does xyz one-line or so
long-summary: |
this module.... kjsdflkj... klsfkj paragraph1
this module.... kjsdflkj... klsfkj paragraph2
parameters:
- name: prm1longlonglong
type: enum
required: true
short-summary: one line partial sentence
long-summary: text, markdown, etc.
populator-commands:
- az vm list
- default
- name: prm2
type: flag
short-summary: one line partial sentence
long-summary: paragraph(s)


"""

return load(s)

def _load_child_delimiters(delimiters):
return [delimiters + '.foo', delimiters + '.bar']

class HelpAuthoringException(Exception):
pass
20 changes: 14 additions & 6 deletions src/azure/cli/_output.py
Original file line number Diff line number Diff line change
@@ -42,6 +42,11 @@ def format_list(obj):
lo = ListOutput()
return lo.dump(obj_list)

def format_unordered_list(obj):
obj_list = obj if isinstance(obj, list) else [obj]
lo = ListOutput()
return lo.dump(obj_list, should_sort=False)

class OutputProducer(object): #pylint: disable=too-few-public-methods

format_dict = {
@@ -127,19 +132,22 @@ def _dump_line(io, line, indent):
io.write(line)
io.write('\n')

def _dump_object(self, io, obj, indent):
def _dump_object(self, io, obj, indent, should_sort=True):
if isinstance(obj, list):
for array_item in obj:
self._dump_object(io, array_item, indent)
self._dump_object(io, array_item, indent, should_sort)
elif isinstance(obj, dict):
obj_fk = {k: self._get_formatted_key(k) for k in obj}
key_width = ListOutput._get_max_key_len(obj_fk.values())
for key in sorted(obj, key=lambda x: ListOutput._sort_key_func(x, obj)):
keys = sorted(obj, key=lambda x: ListOutput._sort_key_func(x, obj)) \
if should_sort \
else obj
for key in keys:
if isinstance(obj[key], dict) or isinstance(obj[key], list):
# complex object
line = '%s :' % (self._get_formatted_key(key).ljust(key_width))
ListOutput._dump_line(io, line, indent)
self._dump_object(io, obj[key] if obj[key] else 'None', indent+1)
self._dump_object(io, obj[key] if obj[key] else 'None', indent+1, should_sort)
else:
# non-complex so write it
line = '%s : %s' % (self._get_formatted_key(key).ljust(key_width),
@@ -148,10 +156,10 @@ def _dump_object(self, io, obj, indent):
else:
ListOutput._dump_line(io, obj, indent)

def dump(self, data):
def dump(self, data, should_sort=True):
io = StringIO()
for obj in data:
self._dump_object(io, obj, 0)
self._dump_object(io, obj, 0, should_sort)
io.write('\n')
result = io.getvalue()
io.close()