Beispiel #1
0
    def test_simple_install(self):
        egg = DUMMY_EGG
        base_egg = os.path.basename(egg)
        fetch_opcode = 0

        entries = [
            EnpkgS3IndexEntry(product="free", build=1,
                              egg_basename="dummy", version="1.0.1",
                              available=True),
        ]

        repo = MetadataOnlyStore(entries)
        repo.connect()

        with mock.patch("enstaller.enpkg.Enpkg.fetch") as mocked_fetch:
            enpkg = Enpkg(repo, prefixes=self.prefixes, hook=None,
                          evt_mgr=None, verbose=False, config=Configuration())
            local_repo = JoinedEggCollection([
                EggCollection(prefix, False, None) for prefix in
                self.prefixes])
            local_repo.install = mock.MagicMock()
            enpkg.ec = local_repo

            actions = enpkg.install_actions("dummy")
            enpkg.execute(actions)

            mocked_fetch.assert_called_with(base_egg, force=fetch_opcode)
            local_repo.install.assert_called_with(base_egg, enpkg.local_dir,
                                                  None)
Beispiel #2
0
    def test_simple_scenario(self):
        egg = DUMMY_EGG
        r_actions = {1: [], 0: [("remove", os.path.basename(egg))]}
        config = Configuration()

        repository = Repository()
        package = RepositoryPackageMetadata.from_egg(egg)
        package.python = PY_VER
        repository.add_package(package)

        with open(egg, "rb") as fp:
            responses.add(responses.GET, package.source_url,
                          body=fp.read(), status=200,
                          content_type='application/json')

        session = Session(DummyAuthenticator(), config.repository_cache)

        enpkg = Enpkg(repository, session, prefixes=self.prefixes)
        actions = [("fetch", os.path.basename(egg)),
                   ("install", os.path.basename(egg))]
        enpkg.execute(actions)

        name, version = egg_name_to_name_version(egg)
        enpkg._installed_repository.find_package(name, version)

        for state in [0, 1]:
            actions = enpkg.revert_actions(state)
            self.assertEqual(actions, r_actions[state])
Beispiel #3
0
    def test_simple_fetch(self):
        egg = "yoyo.egg"
        fetch_opcode = 0

        repo = MetadataOnlyStore([])
        repo.connect()

        with mock.patch("enstaller.enpkg.Enpkg.fetch") as mocked_fetch:
            enpkg = Enpkg(repo, prefixes=self.prefixes, hook=None,
                          evt_mgr=None, verbose=False, config=Configuration())
            enpkg.ec = mock.MagicMock()
            enpkg.execute([("fetch_{0}".format(fetch_opcode), egg)])

            self.assertTrue(mocked_fetch.called)
            mocked_fetch.assert_called_with(egg, force=fetch_opcode)
    def test_abort(self):
        """Ensure calling abort does abort the current set of executed actions."""
        sentinel = []

        def fake_install(*args):
            time.sleep(5)
            sentinel.append("oui oui")

        entries = [
            dummy_repository_package_factory("numpy", "1.6.1", 1),
            dummy_repository_package_factory("numpy", "1.8.0", 2),
        ]
        repository = repository_factory(entries)

        with mock.patch("enstaller.enpkg.FetchAction.execute"):
            with mock.patch("enstaller.enpkg.InstallAction.execute", fake_install):
                enpkg = Enpkg(repository, mock.Mock())
                actions = enpkg._solver.install_actions("numpy")

                t = threading.Thread(target=lambda: enpkg.execute(actions))
                t.start()

                enpkg.abort_execution()
                t.join(timeout=10)

        self.assertEqual(sentinel, [])
Beispiel #5
0
    def test_install_pypi_before_non_pypi(self):
        # Given
        config = Configuration()
        config.update(auth=("nono", "le petit robot"))

        session = Session.from_configuration(config)
        session.authenticate(config.auth)

        repository = repository_factory(session, config.indices)

        enpkg = Enpkg(repository, session, [self.prefix])
        enpkg.execute = mock.Mock()

        # When
        with mock_print() as mocked_print:
            with mock_raw_input("yes"):
                install_req(enpkg, config, "swig 2.0.2", FakeOptions())

        # Then
        self._assert_ask_for_pypi(mocked_print)

        # When
        with mock_print() as mocked_print:
            with mock_raw_input("yes"):
                install_req(enpkg, config, "swig 2.0.2-1", FakeOptions())

        # Then
        self._assert_ask_for_pypi(mocked_print)
Beispiel #6
0
    def test_install_pypi_before_non_pypi(self):
        # Given
        config = Configuration()
        config.update(auth=("nono", "le petit robot"))

        session = Session.from_configuration(config)
        session.authenticate(config.auth)

        repository = repository_factory(session, config.indices)

        enpkg = Enpkg(repository, session, [self.prefix])
        enpkg.execute = mock.Mock()

        # When
        with mock_print() as mocked_print:
            with mock_raw_input("yes"):
                install_req(enpkg, config, "swig 2.0.2", FakeOptions())

        # Then
        self._assert_ask_for_pypi(mocked_print)

        # When
        with mock_print() as mocked_print:
            with mock_raw_input("yes"):
                install_req(enpkg, config, "swig 2.0.2-1", FakeOptions())

        # Then
        self._assert_ask_for_pypi(mocked_print)
Beispiel #7
0
    def test_install_broken_pypi_requirement(self):
        self.maxDiff = None

        # Given
        r_message = textwrap.dedent("""
Broken pypi package 'rednose-0.2.3-1.egg': missing dependency 'python_termstyle'

Pypi packages are not officially supported. If this package is important to
you, please contact Enthought support to request its inclusion in our
officially supported repository.

In the mean time, you may want to try installing 'rednose-0.2.3-1.egg' from sources
with pip as follows:

    $ enpkg pip
    $ pip install <requested_package>

""")

        config = Configuration()
        session = Session.from_configuration(config)
        session.authenticate(("nono", "le petit robot"))
        repository = repository_factory(session, config.indices)

        enpkg = Enpkg(repository, session, [self.prefix])
        enpkg.execute = mock.Mock()

        # When
        with self.assertRaises(SystemExit):
            with mock_print() as mocked_print:
                with mock_raw_input("yes"):
                    install_req(enpkg, config, "rednose", FakeOptions())

        # Then
        self.assertMultiLineEqual(mocked_print.value, r_message)
Beispiel #8
0
    def test_install_broken_pypi_requirement(self):
        self.maxDiff = None

        # Given
        r_message = textwrap.dedent("""
Broken pypi package 'rednose-0.2.3-1.egg': missing dependency 'python_termstyle'

Pypi packages are not officially supported. If this package is important to
you, please contact Enthought support to request its inclusion in our
officially supported repository.

In the mean time, you may want to try installing 'rednose-0.2.3-1.egg' from sources
with pip as follows:

    $ enpkg pip
    $ pip install <requested_package>

""")

        config = Configuration()
        session = Session.from_configuration(config)
        session.authenticate(("nono", "le petit robot"))
        repository = repository_factory(session, config.indices)

        enpkg = Enpkg(repository, session, [self.prefix])
        enpkg.execute = mock.Mock()

        # When
        with self.assertRaises(SystemExit):
            with mock_print() as mocked_print:
                with mock_raw_input("yes"):
                    install_req(enpkg, config, "rednose", FakeOptions())

        # Then
        self.assertMultiLineEqual(mocked_print.value, r_message)
Beispiel #9
0
    def test_simple_scenario(self):
        egg = DUMMY_EGG
        r_actions = {1: [], 0: [("remove", os.path.basename(egg))]}

        repo = EggsStore([egg])
        repo.connect()

        enpkg = Enpkg(repo, prefixes=self.prefixes, hook=None,
                      evt_mgr=None, verbose=False, config=Configuration())
        actions = enpkg.install_actions("dummy")
        enpkg.execute(actions)

        self.assertIsNotNone(enpkg.find(os.path.basename(egg)))

        for state in [0, 1]:
            actions = enpkg.revert_actions(state)
            self.assertEqual(actions, r_actions[state])
Beispiel #10
0
    def test_simple_install(self):
        config = Configuration()
        entries = [
            dummy_repository_package_factory("dummy", "1.0.1", 1)
        ]

        repository = repository_factory(entries)

        with mock.patch("enstaller.enpkg.FetchAction.execute") as mocked_fetch:
            with mock.patch("enstaller.enpkg.InstallAction.execute") as mocked_install:
                enpkg = Enpkg(repository,
                              mocked_session_factory(config.repository_cache),
                              prefixes=self.prefixes)
                actions = [("install", "dummy-1.0.1-1.egg")]
                enpkg.execute(actions)

                mocked_fetch.assert_called()
                mocked_install.assert_called_with()
Beispiel #11
0
def remove():
    """ Remove the given requirement.

    Parameter is expected to be a JSON UTF8 encoded bytestring passed through
    stdin.
    """
    json_string = _read_stdin_as_bytes()
    config, requirement = install_parse_json_string(json_string)

    session = Session.authenticated_from_configuration(config)
    repository = repository_factory(session, config.repositories)

    progress_bar_context = ProgressBarContext(console_progress_manager_factory,
                                              fetch=fetch_progress_factory)
    enpkg = Enpkg(repository, session, [sys.prefix], progress_bar_context, False)

    solver = enpkg._solver_factory()
    try:
        request = Request()
        request.remove(requirement)
        enpkg.execute(solver.resolve(request))
    except NotInstalledPackage as e:
        print(str(e))
Beispiel #12
0
    def test_install_not_available(self):
        # Given
        config = Configuration()
        config.update(auth=FAKE_AUTH)

        nose = dummy_repository_package_factory("nose", "1.3.0", 1)
        nose.available = False
        repository = Repository()
        repository.add_package(nose)

        enpkg = Enpkg(repository,
                      mocked_session_factory(config.repository_cache),
                      [self.prefix])
        enpkg.execute = mock.Mock()

        # When/Then
        with mock.patch("enstaller.config.subscription_message") as \
                subscription_message:
            with self.assertRaises(SystemExit) as e:
                install_req(enpkg, config, "nose", FakeOptions())
            subscription_message.assert_called()
            self.assertEqual(e.exception.code, 1)
Beispiel #13
0
    def test_install_not_available(self):
        # Given
        config = Configuration()
        config.update(auth=FAKE_AUTH)

        nose = dummy_repository_package_factory("nose", "1.3.0", 1)
        nose.available = False
        repository = Repository()
        repository.add_package(nose)

        enpkg = Enpkg(repository,
                      mocked_session_factory(config.repository_cache),
                      [self.prefix])
        enpkg.execute = mock.Mock()

        # When/Then
        with mock.patch("enstaller.config.subscription_message") as \
                subscription_message:
            with self.assertRaises(SystemExit) as e:
                install_req(enpkg, config, "nose", FakeOptions())
            subscription_message.assert_called()
            self.assertEqual(e.exception.code, 1)
Beispiel #14
0
    def test_install_pypi_requirement(self):
        self.maxDiff = None

        # Given
        r_message = textwrap.dedent("""\
        The following packages/requirements are coming from the PyPi repo:

        rednose

        The PyPi repository which contains >10,000 untested ("as is")
        packages. Some packages are licensed under GPL or other licenses
        which are prohibited for some users. Dependencies may not be
        provided. If you need an updated version or if the installation
        fails due to unmet dependencies, the Knowledge Base article
        Installing external packages into Canopy Python
        (https://support.enthought.com/entries/23389761) may help you with
        installing it.

        Are you sure that you wish to proceed?  (y/[n])
        """)

        config = Configuration()
        session = Session.from_configuration(config)
        session.authenticate(("nono", "le petit robot"))
        repository = repository_factory(session, config.indices)

        enpkg = Enpkg(repository, session, [self.prefix])
        enpkg.execute = mock.Mock()

        # When
        with mock_print() as mocked_print:
            with mock_raw_input("yes"):
                install_req(enpkg, config, "rednose", FakeOptions())

        # Then
        self.assertMultiLineEqual(mocked_print.value, r_message)
Beispiel #15
0
    def test_install_pypi_requirement(self):
        self.maxDiff = None

        # Given
        r_message = textwrap.dedent("""\
        The following packages/requirements are coming from the PyPi repo:

        rednose

        The PyPi repository which contains >10,000 untested ("as is")
        packages. Some packages are licensed under GPL or other licenses
        which are prohibited for some users. Dependencies may not be
        provided. If you need an updated version or if the installation
        fails due to unmet dependencies, the Knowledge Base article
        Installing external packages into Canopy Python
        (https://support.enthought.com/entries/23389761) may help you with
        installing it.

        Are you sure that you wish to proceed?  (y/[n])
        """)

        config = Configuration()
        session = Session.from_configuration(config)
        session.authenticate(("nono", "le petit robot"))
        repository = repository_factory(session, config.indices)

        enpkg = Enpkg(repository, session, [self.prefix])
        enpkg.execute = mock.Mock()

        # When
        with mock_print() as mocked_print:
            with mock_raw_input("yes"):
                install_req(enpkg, config, "rednose", FakeOptions())

        # Then
        self.assertMultiLineEqual(mocked_print.value, r_message)
Beispiel #16
0
def main(argv=None):
    if argv is None:
        argv = sys.argv[1:]

    try:
        user_base = site.USER_BASE
    except AttributeError:
        user_base = abs_expanduser('~/.local')

    p = ArgumentParser(description=__doc__)
    p.add_argument('cnames', metavar='NAME', nargs='*',
                   help='package(s) to work on')
    p.add_argument("--add-url", metavar='URL',
                   help="add a repository URL to the configuration file")
    p.add_argument("--config", action="store_true",
                   help="display the configuration and exit")
    p.add_argument('-f', "--force", action="store_true",
                   help="force install the main package "
                        "(not its dependencies, see --forceall)")
    p.add_argument("--forceall", action="store_true",
                   help="force install of all packages "
                        "(i.e. including dependencies)")
    p.add_argument("--freeze", help=argparse.SUPPRESS, action="store_true")
    p.add_argument("--hook", action="store_true",
                   help="don't install into site-packages (experimental)")
    p.add_argument("--imports", action="store_true",
                   help="show which packages can be imported")
    p.add_argument('-i', "--info", action="store_true",
                   help="show information about a package")
    p.add_argument("--log", action="store_true", help="print revision log")
    p.add_argument('-l', "--list", action="store_true",
                   help="list the packages currently installed on the system")
    p.add_argument('-n', "--dry-run", action="store_true",
               help="show what would have been downloaded/removed/installed")
    p.add_argument('-N', "--no-deps", action="store_true",
                   help="neither download nor install dependencies")
    p.add_argument("--env", action="store_true",
                   help="based on the configuration, display how to set "
                        "environment variables")
    p.add_argument("--prefix", metavar='PATH',
                   help="install prefix (disregarding any settings in "
                        "the config file)")
    p.add_argument("--proxy", metavar='PROXYSTR',
                   help="use a proxy for downloads."
                        " <proxy protocol>://[<proxy username>"
                        "[:<proxy password>@]]<proxy server>:<proxy port>")
    p.add_argument("--remove", action="store_true", help="remove a package")
    p.add_argument("--remove-enstaller", action="store_true",
                   help="remove enstaller (will break enpkg)")
    p.add_argument("--requirements", help=argparse.SUPPRESS)
    p.add_argument("--revert", metavar="REV#",
                   help="revert to a previous set of packages (does not revert "
                   "enstaller itself)")
    p.add_argument('-s', "--search", action="store_true",
                   help="search the online repo index "
                        "and display versions available")
    p.add_argument("--sys-config", action="store_true",
                   help="use <sys.prefix>/.enstaller4rc (even when "
                        "~/.enstaller4rc exists)")
    p.add_argument("--sys-prefix", action="store_true",
                   help="use sys.prefix as the install prefix")
    p.add_argument("--update-all", action="store_true",
                   help="update all installed packages")
    p.add_argument("--user", action="store_true",
               help="install into user prefix, i.e. --prefix=%r" % user_base)
    p.add_argument("--userpass", action="store_true",
                   help="prompt for Enthought authentication, and save in "
                   "configuration file .enstaller4rc")
    p.add_argument('-v', "--verbose", action="store_true")
    p.add_argument('--version', action="version",
                   version='enstaller version: ' + __version__)
    p.add_argument("--whats-new", action="store_true",
                   help="display available updates for installed packages")

    args = p.parse_args(argv)

    config_filename = get_config_filename(args.sys_config)
    if not os.path.isfile(config_filename):
        write_default_config(config_filename)

    config = Configuration.from_file(config_filename)

    # Check for incompatible actions and options
    # Action options which take no package name pattern:
    simple_standalone_actions = (args.config, args.env, args.userpass,
                                args.revert, args.log, args.whats_new,
                                args.update_all, args.remove_enstaller,
                                args.add_url, args.freeze, args.requirements)
    # Action options which can take a package name pattern:
    complex_standalone_actions = (args.list, args.imports,
                                 args.search, args.info, args.remove)

    count_simple_actions = sum(bool(opt) for opt in simple_standalone_actions)
    count_complex_actions = sum(bool(opt) for opt in complex_standalone_actions)

    if count_simple_actions + count_complex_actions > 1:
        p.error('Multiple action options specified')
    if count_simple_actions > 0 and len(args.cnames) > 0:
        p.error("Option takes no arguments")

    if args.user:
        args.prefix = user_base

    if args.prefix and args.sys_prefix:
        p.error("Options --prefix and --sys-prefix exclude each other")

    if args.force and args.forceall:
        p.error("Options --force and --forceall exclude each other")

    pat = None
    if (args.list or args.search) and args.cnames:
        pat = re.compile(args.cnames[0], re.I)

    # make prefix
    if args.sys_prefix:
        prefix = sys.prefix
    elif args.prefix:
        prefix = args.prefix
    else:
        prefix = config.prefix

    # now make prefixes
    if prefix == sys.prefix:
        prefixes = [sys.prefix]
    else:
        prefixes = [prefix, sys.prefix]

    if args.user:
        try:
            check_prefixes(prefixes)
        except InvalidPythonPathConfiguration:
            warnings.warn("Using the --user option, but your PYTHONPATH is not setup " \
                          "accordingly")

    exit_if_sudo_on_venv(prefix)

    if args.verbose:
        print("Prefixes:")
        for prefix in prefixes:
            print('    %s%s' % (prefix, ['', ' (sys)'][prefix == sys.prefix]))
        print()

    if args.env:                                  # --env
        env_option(prefixes)
        return

    if args.log:                                  # --log
        if args.hook:
            raise NotImplementedError
        from history import History
        h = History(prefix)
        h.update()
        h.print_log()
        return

    if args.freeze:
        from .eggcollect import EggCollection, JoinedEggCollection
        collection = JoinedEggCollection(
            [EggCollection(prefix, False, None) for prefix in prefixes]
        )
        full_names = [
            "{0} {1}-{2}".format(req["name"], req["version"], req["build"])
            for name, req in collection.query(type="egg")
        ]
        for full_name in sorted(full_names):
            print(full_name)
        return

    if args.list:                                 # --list
        list_option(prefixes, args.hook, pat)
        return

    if args.proxy:                                # --proxy
        setup_proxy(args.proxy)
    elif config.proxy:
        setup_proxy(config.proxy)
    else:
        setup_proxy()

    evt_mgr = None

    if config.use_webservice:
        remote = None # Enpkg will create the default
    else:
        urls = [fill_url(u) for u in config.IndexedRepos]
        remote = create_joined_store(config, urls)

    enpkg = Enpkg(remote, prefixes=prefixes, hook=args.hook,
                  evt_mgr=evt_mgr, verbose=args.verbose, config=config)


    if args.config:                               # --config
        print_config(config, enpkg.remote, prefixes[0])
        return

    if args.add_url:                              # --add-url
        add_url(config_filename, enpkg.config, args.add_url, args.verbose)
        return

    if args.userpass:                             # --userpass
        n_trials = 3
        for i in range(n_trials):
            username, password = input_auth()
            if username:
                break
            else:
                print("Please enter a non empty username ({0} trial(s) left)". \
                      format(n_trials - i - 1))
        else:
            print("No valid username entered (no modification was written).")
            sys.exit(-1)

        config.set_auth(username, password)
        try:
            config._checked_change_auth(config_filename)
        except AuthFailedError as e:
            msg = ("Could not authenticate. Please check your credentials "
                   "and try again.\nNo modification was written.")
            print(msg)
            sys.exit(-1)
        return

    if not config.is_auth_configured:
        print(PLEASE_AUTH_MESSAGE)
        sys.exit(-1)

    try:
        config.get_auth()
    except InvalidConfiguration:
        print(PLEASE_AUTH_MESSAGE)
        sys.exit(-1)
    else:
        try:
            authenticate(config, enpkg.remote)
        except AuthFailedError as e:
            login, _ = config.get_auth()
            print("Could not authenticate with user '{0}'.".format(login))
            print("You can change your authentication details with 'enpkg --userpass'")
            sys.exit(-1)

    if args.dry_run:
        def print_actions(actions):
            for item in actions:
                print('%-8s %s' % item)
        enpkg.execute = print_actions

    if args.imports:                              # --imports
        assert not args.hook
        imports_option(enpkg, pat)
        return

    if args.revert:                               # --revert
        if isfile(args.revert):
            arg = parse_list(args.revert)
        else:
            arg = args.revert
        try:
            actions = enpkg.revert_actions(arg)
            if not actions:
                print("Nothing to do")
                return
            enpkg.execute(actions)
        except EnpkgError as e:
            print(e.message)
        return

    # Try to auto-update enstaller
    if update_enstaller(enpkg, args):
        print("Enstaller has been updated.\n"
              "Please re-run your previous command.")
        return

    if args.search:                               # --search
        search(enpkg, pat)
        return

    if args.info:                                 # --info
        if len(args.cnames) != 1:
            p.error("Option requires one argument (name of package)")
        info_option(enpkg, args.cnames[0])
        return

    if args.whats_new:                            # --whats-new
        whats_new(enpkg)
        return

    if args.update_all:                           # --update-all
        update_all(enpkg, args)
        return

    if args.requirements:
        with open(args.requirements, "r") as fp:
            for req in fp:
                args.no_deps = True
                install_req(enpkg, req, args)
        return

    if len(args.cnames) == 0 and not args.remove_enstaller:
        p.error("Requirement(s) missing")
    elif len(args.cnames) == 2:
        pat = re.compile(r'\d+\.\d+')
        if pat.match(args.cnames[1]):
            args.cnames = ['-'.join(args.cnames)]

    reqs = []
    for arg in args.cnames:
        if '-' in arg:
            name, version = arg.split('-', 1)
            reqs.append(Req(name + ' ' + version))
        else:
            reqs.append(Req(arg))

    # This code assumes we have already upgraded enstaller if needed
    if needs_to_downgrade_enstaller(enpkg, reqs):
        warnings.warn("Enstaller in requirement list: enstaller will be downgraded !")
    else:
        print("Enstaller is already up to date, not upgrading.")
        reqs = [req for req in reqs if req.name != "enstaller"]

    if args.verbose:
        print("Requirements:")
        for req in reqs:
            print('    %r' % req)
        print()

    print("prefix:", prefix)

    REMOVE_ENSTALLER_WARNING = ("Removing enstaller package will break enpkg "
                                "and is not recommended.")
    if args.remove:
        if any(req.name == 'enstaller' for req in reqs):
            print(REMOVE_ENSTALLER_WARNING)
            print("If you are sure you wish to remove enstaller, use:")
            print("    enpkg --remove-enstaller")
            return

    if args.remove_enstaller:
        print(REMOVE_ENSTALLER_WARNING)
        yn = raw_input("Really remove enstaller? (y/[n]) ")
        if yn.lower() in set(['y', 'yes']):
            args.remove = True
            reqs = [Req('enstaller')]

    if any(req.name == 'epd' for req in reqs):
        if args.remove:
            p.error("Can't remove 'epd'")
        elif len(reqs) > 1:
            p.error("Can't combine 'enpkg epd' with other packages.")
            return
        elif not epd_install_confirm():
            return

    for req in reqs:
        if args.remove:                               # --remove
            try:
                enpkg.execute(enpkg.remove_actions(req))
            except EnpkgError as e:
                print(e.message)
        else:
            install_req(enpkg, req, args)             # install (default)
Beispiel #17
0
def main():
    try:
        user_base = site.USER_BASE
    except AttributeError:
        user_base = abs_expanduser('~/.local')

    p = ArgumentParser(description=__doc__)
    p.add_argument('cnames', metavar='NAME', nargs='*',
                   help='package(s) to work on')
    p.add_argument("--add-url", metavar='URL',
                   help="add a repository URL to the configuration file")
    p.add_argument("--config", action="store_true",
                   help="display the configuration and exit")
    p.add_argument('-f', "--force", action="store_true",
                   help="force install the main package "
                        "(not its dependencies, see --forceall)")
    p.add_argument("--forceall", action="store_true",
                   help="force install of all packages "
                        "(i.e. including dependencies)")
    p.add_argument("--hook", action="store_true",
                   help="don't install into site-packages (experimental)")
    p.add_argument("--imports", action="store_true",
                   help="show which packages can be imported")
    p.add_argument('-i', "--info", action="store_true",
                   help="show information about a package")
    p.add_argument("--log", action="store_true", help="print revision log")
    p.add_argument('-l', "--list", action="store_true",
                   help="list the packages currently installed on the system")
    p.add_argument('-n', "--dry-run", action="store_true",
               help="show what would have been downloaded/removed/installed")
    p.add_argument('-N', "--no-deps", action="store_true",
                   help="neither download nor install dependencies")
    p.add_argument("--env", action="store_true",
                   help="based on the configuration, display how to set "
                        "environment variables")
    p.add_argument("--prefix", metavar='PATH',
                   help="install prefix (disregarding any settings in "
                        "the config file)")
    p.add_argument("--proxy", metavar='PROXYSTR',
                   help="use a proxy for downloads."
                        " <proxy protocol>://[<proxy username>"
                        "[:<proxy password>@]]<proxy server>:<proxy port>")
    p.add_argument("--remove", action="store_true", help="remove a package")
    p.add_argument("--remove-enstaller", action="store_true",
                   help="remove enstaller (will break enpkg)")
    p.add_argument("--revert", metavar="REV#",
                   help="revert to a previous set of packages (does not revert "
                   "enstaller itself)")
    p.add_argument('-s', "--search", action="store_true",
                   help="search the online repo index "
                        "and display versions available")
    p.add_argument("--sys-config", action="store_true",
                   help="use <sys.prefix>/.enstaller4rc (even when "
                        "~/.enstaller4rc exists)")
    p.add_argument("--sys-prefix", action="store_true",
                   help="use sys.prefix as the install prefix")
    p.add_argument("--update-all", action="store_true",
                   help="update all installed packages")
    p.add_argument("--user", action="store_true",
               help="install into user prefix, i.e. --prefix=%r" % user_base)
    p.add_argument("--userpass", action="store_true",
                   help="prompt for Enthought authentication, and save in "
                   "configuration file .enstaller4rc")
    p.add_argument('-v', "--verbose", action="store_true")
    p.add_argument('--version', action="version",
                   version='enstaller version: ' + __version__)
    p.add_argument("--whats-new", action="store_true",
                   help="display available updates for installed packages")

    args = p.parse_args()

    # Check for incompatible actions and options
    # Action options which take no package name pattern:
    simple_standalone_actions = (args.config, args.env, args.userpass,
                                args.revert, args.log, args.whats_new,
                                args.update_all, args.remove_enstaller,
                                args.add_url)
    # Action options which can take a package name pattern:
    complex_standalone_actions = (args.list, args.imports,
                                 args.search, args.info, args.remove)

    count_simple_actions = sum(bool(opt) for opt in simple_standalone_actions)
    count_complex_actions = sum(bool(opt) for opt in complex_standalone_actions)

    if count_simple_actions + count_complex_actions > 1:
        p.error('Multiple action options specified')
    if count_simple_actions > 0 and len(args.cnames) > 0:
        p.error("Option takes no arguments")

    if args.user:
        args.prefix = user_base

    if args.prefix and args.sys_prefix:
        p.error("Options --prefix and --sys-prefix exclude each other")

    if args.force and args.forceall:
        p.error("Options --force and --forceall exclude each other")

    pat = None
    if (args.list or args.search) and args.cnames:
        pat = re.compile(args.cnames[0], re.I)

    # make prefix
    if args.sys_prefix:
        prefix = sys.prefix
    elif args.prefix:
        prefix = args.prefix
    else:
        prefix = config.get('prefix', sys.prefix)

    # now make prefixes
    if prefix == sys.prefix:
        prefixes = [sys.prefix]
    else:
        prefixes = [prefix, sys.prefix]

    exit_if_sudo_on_venv(prefix)

    if args.verbose:
        print "Prefixes:"
        for prefix in prefixes:
            print '    %s%s' % (prefix, ['', ' (sys)'][prefix == sys.prefix])
        print

    if args.env:                                  # --env
        env_option(prefixes)
        return

    if args.log:                                  # --log
        if args.hook:
            raise NotImplementedError
        from history import History
        h = History(prefix)
        h.update()
        h.print_log()
        return

    if args.sys_config:                           # --sys-config
        config.get_path = lambda: config.system_config_path

    if args.list:                                 # --list
        list_option(prefixes, args.hook, pat)
        return

    if args.proxy:                                # --proxy
        setup_proxy(args.proxy)
    elif config.get('proxy'):
        setup_proxy(config.get('proxy'))
    else:
        setup_proxy()

    if 0: # for testing event manager only
        from encore.events.api import EventManager
        from encore.terminal.api import ProgressDisplay
        evt_mgr = EventManager()
        display = ProgressDisplay(evt_mgr)
    else:
        evt_mgr = None

    if config.get('use_webservice'):
        remote = None # Enpkg will create the default
    else:
        urls = [fill_url(u) for u in config.get('IndexedRepos')]
        remote = create_joined_store(urls)

    enpkg = Enpkg(remote, prefixes=prefixes, hook=args.hook,
                  evt_mgr=evt_mgr, verbose=args.verbose)


    if args.config:                               # --config
        config.print_config(enpkg.remote, prefixes[0])
        return

    if args.userpass:                             # --userpass
        username, password = config.input_auth()
        config.checked_change_auth(username, password, enpkg.remote)
        return

    if args.dry_run:
        def print_actions(actions):
            for item in actions:
                print '%-8s %s' % item
        enpkg.execute = print_actions

    if args.imports:                              # --imports
        assert not args.hook
        imports_option(enpkg, pat)
        return

    if args.add_url:                              # --add-url
        add_url(args.add_url, args.verbose)
        return

    if args.revert:                               # --revert
        if isfile(args.revert):
            arg = parse_list(args.revert)
        else:
            arg = args.revert
        try:
            actions = enpkg.revert_actions(arg)
            if not actions:
                print "Nothing to do"
                return
            enpkg.execute(actions)
        except EnpkgError as e:
            print e.message
        return

    # Try to auto-update enstaller
    if update_enstaller(enpkg, args):
        print "Enstaller has been updated.", \
            "Please re-run your previous command."
        return

    if args.search:                               # --search
        search(enpkg, pat)
        return

    if args.info:                                 # --info
        if len(args.cnames) != 1:
            p.error("Option requires one argument (name of package)")
        info_option(enpkg, args.cnames[0])
        return

    if args.whats_new:                            # --whats-new
        whats_new(enpkg)
        return

    if args.update_all:                           # --update-all
        update_all(enpkg, args)
        return

    if len(args.cnames) == 0 and not args.remove_enstaller:
        p.error("Requirement(s) missing")
    elif len(args.cnames) == 2:
        pat = re.compile(r'\d+\.\d+')
        if pat.match(args.cnames[1]):
            args.cnames = ['-'.join(args.cnames)]

    reqs = []
    for arg in args.cnames:
        if '-' in arg:
            name, version = arg.split('-', 1)
            reqs.append(Req(name + ' ' + version))
        else:
            reqs.append(Req(arg))

    if args.verbose:
        print "Requirements:"
        for req in reqs:
            print '    %r' % req
        print

    print "prefix:", prefix

    REMOVE_ENSTALLER_WARNING = ("Removing enstaller package will break enpkg "
                                "and is not recommended.")
    if args.remove:
        if any(req.name == 'enstaller' for req in reqs):
            print REMOVE_ENSTALLER_WARNING
            print "If you are sure you wish to remove enstaller, use:"
            print "    enpkg --remove-enstaller"
            return

    if args.remove_enstaller:
        print REMOVE_ENSTALLER_WARNING
        yn = raw_input("Really remove enstaller? (y/[n]) ")
        if yn.lower() in set(['y', 'yes']):
            args.remove = True
            reqs = [Req('enstaller')]

    if any(req.name == 'epd' for req in reqs):
        if args.remove:
            p.error("Can't remove 'epd'")
        elif len(reqs) > 1:
            p.error("Can't combine 'enpkg epd' with other packages.")
            return
        elif not epd_install_confirm():
            return

    for req in reqs:
        if args.remove:                               # --remove
            try:
                enpkg.execute(enpkg.remove_actions(req))
            except EnpkgError as e:
                print e.message
        else:
            install_req(enpkg, req, args)             # install (default)