Skip to content

Commit

Permalink
Noarch install getting closer
Browse files Browse the repository at this point in the history
  • Loading branch information
kalefranz committed Nov 8, 2016
1 parent f7fdab5 commit d920df6
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 48 deletions.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ include MANIFEST.in
include README.rst
include setup.cfg
include setup.py
include conda/resources/*
include shell/*
recursive-exclude tests *
4 changes: 3 additions & 1 deletion conda/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@

import os
import sys
from os.path import dirname

from ._vendor.auxlib.packaging import get_version
from .compat import text_type, iteritems
from .compat import iteritems, text_type
from .gateways.logging import initialize_logging

__all__ = [
Expand All @@ -29,6 +30,7 @@

if os.getenv('CONDA_ROOT') is None:
os.environ['CONDA_ROOT'] = sys.prefix
PACKAGE_ROOT = dirname(__file__)

initialize_logging()

Expand Down
10 changes: 9 additions & 1 deletion conda/common/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

from functools import reduce
from logging import getLogger
from os.path import dirname, basename
from os.path import basename, dirname, join

from ..utils import on_win

log = getLogger(__name__)

Expand Down Expand Up @@ -58,3 +60,9 @@ def parse_entry_point_def(ep_definition):
return command, module, func


def get_python_path(prefix):
return join(prefix, "python.exe") if on_win else join(prefix, "bin", "python")


def get_bin_directory(prefix):
return join(prefix, 'Scripts') if on_win else join(prefix, 'bin')
60 changes: 36 additions & 24 deletions conda/core/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
from .package_cache import is_extracted, read_url
from ..base.constants import LinkType
from ..base.context import context
from ..common.path import get_leaf_directories
from ..core.linked_data import set_linked_data, get_python_version_for_prefix
from ..common.path import get_bin_directory, get_leaf_directories
from ..core.linked_data import get_python_version_for_prefix, set_linked_data
from ..exceptions import CondaOSError, LinkError, PaddingError
from ..gateways.disk.create import link as create_link, make_menu, mkdir_p, write_conda_meta_record, \
compile_missing_pyc
from ..gateways.disk.create import (compile_missing_pyc, create_entry_point, link as create_link,
make_menu, mkdir_p, write_conda_meta_record)
from ..gateways.disk.delete import rm_rf
from ..gateways.disk.read import collect_all_info_for_package, yield_lines
from ..gateways.disk.update import _PaddingError, update_prefix
Expand All @@ -37,12 +37,22 @@
'prefix_placeholder', 'file_mode', 'is_menu_file'))


def get_package_installer(prefix, index, dist):
# a factory-type function for getting the correct PackageInstaller class
record = index[dist]
if record.noarch and record.noarch.lower() == 'python':
return NoarchPythonPackageInstaller(prefix, index, dist)
else:
return PackageInstaller(prefix, index, dist)


class PackageInstaller(object):

def __init__(self, prefix, index, dist):
self.prefix = prefix
self.index = index
self.dist = dist
self.package_info = None # set in the link method

def link(self, requested_link_type=LinkType.hard_link):
log.debug("linking package %s with link type %s", self.dist, requested_link_type)
Expand All @@ -55,20 +65,20 @@ def link(self, requested_link_type=LinkType.hard_link):
self.prefix, extracted_package_dir, requested_link_type)

# filesystem read actions
# do all filesystem reads necessaary for the rest of the linking for this package
package_info = collect_all_info_for_package(extracted_package_dir)
url = read_url(self.dist)
# do all filesystem reads necessary for the rest of the linking for this package
self.package_info = collect_all_info_for_package(extracted_package_dir)
url = read_url(self.dist) # TODO: consider making this part of package_info

# simple processing
operations = self._make_link_operations(self.prefix, requested_link_type, package_info)
operations = self._make_link_operations(requested_link_type, package_info)
leaf_directories = get_leaf_directories(join(self.prefix, op.dest_short_path)
for op in operations)

# run pre-link script
if not run_script(extracted_package_dir, self.dist, 'pre-link', self.prefix):
raise LinkError('Error: pre-link failed: %s' % self.dist)
# # run pre-link script
# if not run_script(extracted_package_dir, self.dist, 'pre-link', self.prefix):
# raise LinkError('Error: pre-link failed: %s' % self.dist)

dest_short_paths = self._execute_link_operations(self.prefix, leaf_directories, operations)
dest_short_paths = self._execute_link_operations(leaf_directories, operations)

# run post-link script
if not run_script(self.prefix, self.dist, 'post-link'):
Expand All @@ -81,6 +91,7 @@ def link(self, requested_link_type=LinkType.hard_link):
set_linked_data(self.prefix, self.dist.dist_name, meta_record)

def _make_link_operations(self, requested_link_type, package_info):
# no side effects in this method!
def make_link_operation(source_short_path):
if source_short_path in package_info.has_prefix_files:
link_type = LinkType.copy
Expand All @@ -99,6 +110,8 @@ def make_link_operation(source_short_path):
return (make_link_operation(p) for p in package_info.files)

def _execute_link_operations(self, leaf_directories, link_operations):
# major side-effects in this method

dest_short_paths = []

# Step 1. Make all directories
Expand Down Expand Up @@ -164,9 +177,11 @@ class NoarchPythonPackageInstaller(PackageInstaller):

def _make_link_operations(self, requested_link_type, package_info):
site_packages_dir = NoarchPythonPackageInstaller.get_site_packages_dir(self.prefix)
bin_dir = NoarchPythonPackageInstaller.get_bin_dir(self.prefix)
bin_dir = get_bin_directory(self.prefix)

def make_link_operation(source_short_path):
# no side effects in this method!

# first part, same as parent class
if source_short_path in package_info.has_prefix_files:
link_type = LinkType.copy
Expand Down Expand Up @@ -199,25 +214,22 @@ def _execute_link_operations(self, leaf_directories, link_operations):
python_veresion = get_python_version_for_prefix(self.prefix)
extra_pyc_paths = compile_missing_pyc(self.prefix, python_veresion,
(op.dest_short_path for op in link_operations))
entry_point_paths = create_entry_points(src_dir, bin_dir, prefix)

# create entry points
entry_points = self.package_info.noarch.get('entry_points', ())
entry_point_paths = []
for entry_point in entry_points:
entry_point_paths.extend(create_entry_point(entry_point, self.prefix))

return sorted(dest_short_paths, extra_pyc_paths, entry_point_paths)


@staticmethod
def get_site_packages_dir(prefix):
if on_win:
return join(prefix, 'Lib')
return join(prefix, 'Lib', 'site-packages')
else:
return join(prefix, 'lib', 'python%s' % get_python_version_for_prefix(prefix))

@staticmethod
def get_bin_dir(prefix):
if on_win:
return join(prefix, 'Scripts')
else:
return join(prefix, 'bin')

return join(prefix, 'lib', 'python%s' % get_python_version_for_prefix(prefix), 'site-packages')



Expand Down
47 changes: 34 additions & 13 deletions conda/gateways/disk/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@
import json
import shutil
import traceback
from conda._vendor.auxlib.ish import dals
from conda._vendor.auxlib.packaging import call
from conda.common.path import missing_pyc_files
from errno import EEXIST
from io import open
from logging import getLogger
from os import W_OK, access, getpid, link as os_link, makedirs, readlink, symlink
from os import W_OK, access, chmod, getpid, link as os_link, makedirs, readlink, symlink
from os.path import basename, exists, isdir, isfile, islink, join

from ... import CondaError
from ... import CondaError, PACKAGE_ROOT
from ..._vendor.auxlib.entity import EntityEncoder
from ..._vendor.auxlib.ish import dals
from ..._vendor.auxlib.packaging import call
from ...base.constants import LinkType
from ...base.context import context
from ...common.path import get_bin_directory, missing_pyc_files, parse_entry_point_def
from ...exceptions import ClobberError, CondaOSError
from ...gateways.disk.delete import backoff_unlink, rm_rf
from ...models.dist import Dist
Expand All @@ -26,18 +27,38 @@


entry_point_template = dals("""
#!(python_exe)s
# -*- coding: utf-8 -*-
import re
import sys
from %(module)s import %(func)s
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(%(func)s())
from sys import exit
from %(module)s import %(func)s
exit(%(func)s())
""")


def create_entry_point(entry_point_def, prefix):
# returns a list of file paths created
command, module, func = parse_entry_point_def(entry_point_def)
ep_path = join(get_bin_directory(prefix), command)

pyscript = entry_point_template % {'module': module, 'func': func}

if on_win:
# create -script.py
with open(ep_path + '-script.py', 'w') as fo:
fo.write(pyscript)

# link cli-XX.exe
link(join(PACKAGE_ROOT, 'resources', 'cli-%d.exe' % context.bits), ep_path + '.exe')
return [ep_path + '-script.py', ep_path + '.exe']
else:
# create py file
with open(ep_path, 'w') as fo:
fo.write('#!%s\n' % join(get_bin_directory(prefix), 'python'))
fo.write(pyscript)
chmod(ep_path, 0o755)
return [ep_path]


def write_conda_meta_record(prefix, record):
# write into <env>/conda-meta/<dist>.json
meta_dir = join(prefix, 'conda-meta')
Expand Down
2 changes: 1 addition & 1 deletion conda/gateways/disk/delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from shutil import rmtree
from uuid import uuid4

from . import exp_backoff_fn, MAX_TRIES
from . import MAX_TRIES, exp_backoff_fn
from .permissions import make_writable, recursive_make_writable
from ...base.context import context
from ...common.compat import text_type
Expand Down
8 changes: 2 additions & 6 deletions conda/gateways/disk/read.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
import shlex
from base64 import b64encode
from collections import namedtuple
from conda.models.record import Record
from errno import ENOENT
from itertools import chain
from logging import getLogger
from os.path import isfile, islink, join

from ...base.constants import FileMode, PREFIX_PLACEHOLDER, UTF8
from ...models.package_info import PackageInfoContents
from ...models.record import Record

log = getLogger(__name__)

Expand Down Expand Up @@ -40,11 +41,6 @@ def yield_lines(path):
raise


PackageInfoContents = namedtuple('PackageInfoContents',
('files', 'has_prefix_files', 'no_link', 'soft_links',
'index_json_record', 'icondata', 'noarch'))


def collect_all_info_for_package(extracted_package_directory):
info_dir = join(extracted_package_directory, 'info')

Expand Down
5 changes: 3 additions & 2 deletions conda/instructions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from .base.constants import LinkType
from .base.context import context
from .core.install import PackageInstaller
from .core.install import get_package_installer
from .core.package_cache import extract, fetch_pkg, is_extracted, rm_extracted, rm_fetched
from .install import symlink_conda, unlink
from .models.dist import Dist
Expand Down Expand Up @@ -82,7 +82,8 @@ def LINK_CMD(state, arg):
dist, lt = split_linkarg(arg)
dist, lt = Dist(dist), LinkType.make(lt)
log.debug("=======> LINKING %s <=======", dist)
PackageInstaller(state['prefix'], state['index'], dist).link(lt)
installer = get_package_installer(state['prefix'], state['index'], dist)
installer.link(lt)


def UNLINK_CMD(state, arg):
Expand Down
21 changes: 21 additions & 0 deletions conda/models/package_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals

from collections import namedtuple
from logging import getLogger

from .._vendor.auxlib.entity import Entity, ListField
from ..common.compat import string_types

log = getLogger(__name__)


PackageInfoContents = namedtuple('PackageInfoContents',
('files', 'has_prefix_files', 'no_link', 'soft_links',
'index_json_record', 'icondata', 'noarch'))


class PackageInfo(Entity):

file = ListField(string_types)
# TODO: finish this
File renamed without changes.
File renamed without changes.

0 comments on commit d920df6

Please sign in to comment.