<commit_before># Copyright (c) 2017 <NAME>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from __future__ import print_function

import click
import collections
import getpass
import json
import os
import six

from six.moves import input
from sys import exit

manifest = require('./lib/manifest')
semver = require('./lib/semver')
refstring = require('./lib/refstring')
config = require('./lib/config')
logger = require('./lib/logger')
_install = require('./lib/install')
registry = require('./lib/registry')

PackageLifecycle = require('./lib/package-lifecycle')


class Less(object):
  # http://stackoverflow.com/a/3306399/791713
  def __init__(self, num_lines):
    self.num_lines = num_lines
  def __ror__(self, other):
    s = six.text_type(other).split("\n")
    for i in range(0, len(s), self.num_lines):
      print("\n".join(s[i:i+self.num_lines]))
      input("Press <Enter> for more")


def get_install_location(global_, root):
  if global_ and root:
    print('Error: -g,--global and --root can not be used together')
    exit(1)
  elif global_:
    if _install.is_virtualenv():
      print('Note: detected virtual environment, upgrading -g,--global to --root')
      return 'root'
    return 'global'
  elif root:
    return 'root'
  else:
    return 'local'


def get_installer(global_, root, upgrade, pip_separate_process,
                  pip_use_target_option, recursive):
  location = get_install_location(global_, root)
  return _install.Installer(upgrade=upgrade, install_location=location,
      pip_separate_process=pip_separate_process,
      pip_use_target_option=pip_use_target_option, recursive=recursive)


@click.group()
def main():
  if not config['registry'].startswith('https://'):
    logger.warning('config value `registry` is not an HTTPS url ({})'
        .format(config['registry']))


@main.command('pip-install', context_settings={'ignore_unknown_options': True})
@click.argument('args', nargs=-1)  # Todo: Consume all arguments followed by the first positional argument
@click.option('-g', '--global/--local', 'global_', is_flag=True)
@click.option('--root', is_flag=True)
def pip_install(args, global_, root):
  """
  Access to Pip, pre-configured for the local Node.py environment.
  """

  installer = get_installer(global_, root, False, False, False, False)
  return installer.install_python_dependencies({}, args)


@main.command()
@click.argument('packages', nargs=-1)
@click.option('-e', '--develop', is_flag=True)
@click.option('-U', '--upgrade', is_flag=True)
@click.option('-g', '--global/--local', 'global_', is_flag=True)
@click.option('--root', is_flag=True)
@click.option('--recursive', is_flag=True,
    help='Satisfy dependencies of already satisfied dependencies.')
@click.option('--pip-separate-process', is_flag=True)
@click.option('--pip-use-target-option', is_flag=True,
    help='Use --target instead of --prefix when installing dependencies '
      'via Pip. This is to circumvent a Bug in Pip where installing with '
      '--prefix fails. See nodepy/ppym#9.')
@click.option('--info', is_flag=True)
@click.option('--dev/--production', 'dev', default=None,
    help='Specify whether to install development dependencies or not. The '
      'default value depends on the installation type (--dev when no packages '
      'are specified, --production otherwise).')
@click.option('--save', is_flag=True)
@click.option('--save-dev', is_flag=True)
def install(packages, develop, upgrade, global_, root, recursive,
            info, dev, pip_separate_process, pip_use_target_option, save,
            save_dev):
  """
  Installs one or more packages.
  """

  if save and save_dev:
    print('Error: decide for either --save or --save-dev')
    return 1
  if save or save_dev:
    if not os.path.isfile('package.json'):
      print('Error: can not --save or --save-dev without a package.json')
      return 1
    with open('package.json') as fp:
      package_json = json.load(fp, object_pairs_hook=collections.OrderedDict)

  if dev is None:
    dev = not packages

  installer = get_installer(global_, root, upgrade, pip_separate_process,
      pip_use_target_option, recursive)
  if info:
    for key in sorted(installer.dirs):
      print('{}: {}'.format(key, installer.dirs[key]))
    return 0

  if not packages:
    success = installer.install_dependencies_for(manifest.parse('package.json'), dev=dev)
    if not success:
      return 1
    installer.relink_pip_scripts()
    return 0

  save_deps = []
  for package in packages:
    if package.startswith('git+'):
      success, package_info = installer.install_from_git(package[4:])
      if success:
        save_deps.append((package_info[0], package))
    elif os.path.isdir(package):
      success = installer.install_from_directory(package, develop, dev=dev)
    elif os.path.isfile(package):
      success = installer.install_from_archive(package, dev=dev)
    else:
      ref = refstring.parse(package)
      selector = ref.version or semver.Selector('*')
      success, package_info = installer.install_from_registry(six.text_type(ref.package), selector, dev=dev)
      if success:
        save_deps.append((package_info[0], '^' + str(package_info[1])))
    if not success:
      print('Installation failed')
      return 1

  installer.relink_pip_scripts()

  if save or save_dev:
    save_deps.sort(key=lambda x: x[0])

    field = 'dependencies' if save else 'dev-dependencies'
    print('Saving "{}"'.format(field))
    for key, value in save_deps:
      print('  "{}": "{}"'.format(key, value))

    have_deps = package_json.get(field, {})
    have_deps.update(dict(save_deps))
    have_deps = sorted(have_deps.items(), key=lambda x: x[0])

    package_json[field] = collections.OrderedDict(have_deps)
    with open('package.json', 'w') as fp:
      json.dump(package_json, fp, indent=2)

  print()
  return 0


@main.command()
@click.argument('package')
@click.option('-g', '--global', 'global_', is_flag=True)
@click.option('--root', is_flag=True)
def uninstall(package, global_, root):
  """
  Uninstall a module with the specified name from the local package directory.
  To uninstall the module from the global package directory, specify
  -g/--global.
  """

  location = get_install_location(global_, root)
  installer = _install.Installer(install_location=location)
  installer.uninstall(package)


@main.command()
def dist():
  """
  Create a .tar.gz distribution from the package.<commit_msg>add -P,--packagedir option to 'ppym install'<commit_after># Copyright (c) 2017 <NAME>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from __future__ import print_function

import click
import collections
import getpass
import json
import os
import six

from six.moves import input
from sys import exit

manifest = require('./lib/manifest')
semver = require('./lib/semver')
refstring = require('./lib/refstring')
config = require('./lib/config')
logger = require('./lib/logger')
_install = require('./lib/install')
registry = require('./lib/registry')

PackageLifecycle = require('./lib/package-lifecycle')


class Less(object):
  # http://stackoverflow.com/a/3306399/791713
  def __init__(self, num_lines):
    self.num_lines = num_lines
  def __ror__(self, other):
    s = six.text_type(other).split("\n")
    for i in range(0, len(s), self.num_lines):
      print("\n".join(s[i:i+self.num_lines]))
      input("Press <Enter> for more")


def get_install_location(global_, root):
  if global_ and root:
    print('Error: -g,--global and --root can not be used together')
    exit(1)
  elif global_:
    if _install.is_virtualenv():
      print('Note: detected virtual environment, upgrading -g,--global to --root')
      return 'root'
    return 'global'
  elif root:
    return 'root'
  else:
    return 'local'


def get_installer(global_, root, upgrade, pip_separate_process,
                  pip_use_target_option, recursive):
  location = get_install_location(global_, root)
  return _install.Installer(upgrade=upgrade, install_location=location,
      pip_separate_process=pip_separate_process,
      pip_use_target_option=pip_use_target_option, recursive=recursive)


@click.group()
def main():
  if not config['registry'].startswith('https://'):
    logger.warning('config value `registry` is not an HTTPS url ({})'
        .format(config['registry']))


@main.command('pip-install', context_settings={'ignore_unknown_options': True})
@click.argument('args', nargs=-1)  # Todo: Consume all arguments followed by the first positional argument
@click.option('-g', '--global/--local', 'global_', is_flag=True)
@click.option('--root', is_flag=True)
def pip_install(args, global_, root):
  """
  Access to Pip, pre-configured for the local Node.py environment.
  """

  installer = get_installer(global_, root, False, False, False, False)
  return installer.install_python_dependencies({}, args)


@main.command()
@click.argument('packages', nargs=-1)
@click.option('-e', '--develop', is_flag=True)
@click.option('-U', '--upgrade', is_flag=True)
@click.option('-g', '--global/--local', 'global_', is_flag=True)
@click.option('-P', '--packagedir', default='.',
    help='The directory to read/write the package.json to/from.')
@click.option('--root', is_flag=True)
@click.option('--recursive', is_flag=True,
    help='Satisfy dependencies of already satisfied dependencies.')
@click.option('--pip-separate-process', is_flag=True)
@click.option('--pip-use-target-option', is_flag=True,
    help='Use --target instead of --prefix when installing dependencies '
      'via Pip. This is to circumvent a Bug in Pip where installing with '
      '--prefix fails. See nodepy/ppym#9.')
@click.option('--info', is_flag=True)
@click.option('--dev/--production', 'dev', default=None,
    help='Specify whether to install development dependencies or not. The '
      'default value depends on the installation type (--dev when no packages '
      'are specified, --production otherwise).')
@click.option('--save', is_flag=True)
@click.option('--save-dev', is_flag=True)
def install(packages, develop, upgrade, global_, packagedir, root, recursive,
            info, dev, pip_separate_process, pip_use_target_option, save,
            save_dev):
  """
  Installs one or more packages.
  """

  packagefile = os.path.join(packagedir, 'package.json')

  if save and save_dev:
    print('Error: decide for either --save or --save-dev')
    return 1
  if save or save_dev:
    if not os.path.isfile(packagefile):
      print('Error: can not --save or --save-dev without a package.json')
      return 1
    with open(packagefile) as fp:
      package_json = json.load(fp, object_pairs_hook=collections.OrderedDict)

  if dev is None:
    dev = not packages

  installer = get_installer(global_, root, upgrade, pip_separate_process,
      pip_use_target_option, recursive)
  if info:
    for key in sorted(installer.dirs):
      print('{}: {}'.format(key, installer.dirs[key]))
    return 0

  if not packages:
    success = installer.install_dependencies_for(manifest.parse(packagefile), dev=dev)
    if not success:
      return 1
    installer.relink_pip_scripts()
    return 0

  save_deps = []
  for package in packages:
    if package.startswith('git+'):
      success, package_info = installer.install_from_git(package[4:])
      if success:
        save_deps.append((package_info[0], package))
    elif os.path.isdir(package):
      success = installer.install_from_directory(package, develop, dev=dev)
    elif os.path.isfile(package):
      success = installer.install_from_archive(package, dev=dev)
    else:
      ref = refstring.parse(package)
      selector = ref.version or semver.Selector('*')
      success, package_info = installer.install_from_registry(six.text_type(ref.package), selector, dev=dev)
      if success:
        save_deps.append((package_info[0], '^' + str(package_info[1])))
    if not success:
      print('Installation failed')
      return 1

  installer.relink_pip_scripts()

  if save or save_dev:
    save_deps.sort(key=lambda x: x[0])

    field = 'dependencies' if save else 'dev-dependencies'
    print('Saving "{}"'.format(field))
    for key, value in save_deps:
      print('  "{}": "{}"'.format(key, value))

    have_deps = package_json.get(field, {})
    have_deps.update(dict(save_deps))
    have_deps = sorted(have_deps.items(), key=lambda x: x[0])

    package_json[field] = collections.OrderedDict(have_deps)
    with open(packagefile, 'w') as fp:
      json.dump(package_json, fp, indent=2)

  print()
  return 0


@main.command()
@click.argument('package')
@click.option('-g', '--global', 'global_', is_flag=True)
@click.option('--root', is_flag=True)
def uninstall(package, global_, root):
  """
  Uninstall a module with the specified name from the local package directory.
  To uninstall the module from the global package directory, specify
  -g/--global.
  """

  location = get_install_location(global_, root)
  installer = _install.Installer(install_location=location)
  installer.uninstall(package)


@main.command()
def dist():
  """
  Create a .tar.gz distribution from the package.
{'fraction_non_alphanumeric': 0.12816602572603103, 'fraction_numerical': 0.004773902665428988, 'mean_word_length': 4.104230118443317, 'pattern_counts': {'":': 2, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5148450', 'n_tokens_mistral': 4732, 'n_tokens_neox': 4542, 'n_words': 1358}