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

Noarch #317

Merged
merged 40 commits into from
Feb 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
439e986
remove call to noarch module
ilanschnell Jan 29, 2015
01e884e
add noarch example
ilanschnell Jan 29, 2015
1dfd191
add 'subdir' key to index.json
ilanschnell Jan 29, 2015
026928c
make use of Python in pre-link script
ilanschnell Jan 30, 2015
aa0f16c
add unlinkage of entry scripts
ilanschnell Jan 30, 2015
6c42a98
add linking site-packages files
ilanschnell Jan 30, 2015
a4e5dc8
update example to bokeh
ilanschnell Jan 30, 2015
a9d91b1
check for 'py_'
ilanschnell Jan 30, 2015
d270851
handle examples also
ilanschnell Jan 30, 2015
1b0689d
add removal of files
ilanschnell Jan 30, 2015
2ab590e
add tests to noarch example
ilanschnell Jan 30, 2015
f8e26df
fix name
ilanschnell Jan 30, 2015
8bc3c2c
use existing script instead creating new entry_point
ilanschnell Jan 30, 2015
a7849fe
better error handling
ilanschnell Jan 30, 2015
3cbc251
add test dependency
ilanschnell Jan 30, 2015
0b1670b
minor simplifiations
ilanschnell Jan 31, 2015
ce385fc
Py3k fixes
ilanschnell Jan 31, 2015
a8f1165
bump build number in example
ilanschnell Jan 31, 2015
5dc3c55
fixed some bugs on Windows
ilanschnell Jan 31, 2015
74418d7
noarch packages cannot have prefix files
ilanschnell Jan 31, 2015
93100ec
fix backslashed in Windows bat files
ilanschnell Jan 31, 2015
4e4552a
add name variable to reduce method calls
ilanschnell Jan 31, 2015
9ecb85f
include data in link.py
ilanschnell Jan 31, 2015
d6e8f68
fixing unlink
ilanschnell Jan 31, 2015
18a2b09
add missing quotes in Windows .bat file
ilanschnell Jan 31, 2015
05a3e50
remove unused code
ilanschnell Jan 31, 2015
ec9233a
some cleanup
ilanschnell Jan 31, 2015
d1bad2a
simplified unlinkage immensely
ilanschnell Feb 1, 2015
bbc1f7f
no need to treat entry points special anymore
ilanschnell Feb 1, 2015
dfa6dac
remove excess lines
ilanschnell Feb 1, 2015
5480a45
fixed Windows filename
ilanschnell Feb 1, 2015
318bd16
remove extra link()
ilanschnell Feb 1, 2015
7f9f31b
improve error handling
ilanschnell Feb 1, 2015
af2f821
add checking for .so files
ilanschnell Feb 1, 2015
911e6df
create new function for rewriting Python script
ilanschnell Feb 1, 2015
dc7d8fe
remove local variable
ilanschnell Feb 1, 2015
33c38f8
exit with error message when on Windows
ilanschnell Feb 1, 2015
98fe00f
add removal of .pyc files
ilanschnell Feb 2, 2015
74b1daa
fix pyc removal for Py3k
ilanschnell Feb 2, 2015
9fa1e24
noarch -> noarch_python
ilanschnell Feb 2, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
100 changes: 100 additions & 0 deletions conda_build/_link.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import os
import sys
import shutil
from os.path import dirname, exists, isdir, join, normpath


THIS_DIR = dirname(__file__)
PREFIX = normpath(sys.prefix)
if sys.platform == 'win32':
BIN_DIR = join(PREFIX, 'Scripts')
SITE_PACKAGES = 'Lib/site-packages'
else:
BIN_DIR = join(PREFIX, 'bin')
SITE_PACKAGES = 'lib/python%s/site-packages' % sys.version[:3]

# the list of these files is going to be store in info/_files
FILES = []


def _link(src, dst):
try:
os.link(src, dst)
# on Windows os.link raises AttributeError
except (OSError, AttributeError):
shutil.copy2(src, dst)


def _unlink(path):
try:
os.unlink(path)
except OSError:
pass


def pyc_f(f):
if sys.version_info[0] == 2:
return f + 'c'
dn, fn = f.rsplit('/', 1)
return '%s/__pycache__/%s.cpython-%d%d.pyc' % (
dn, fn[:-3], sys.version_info[0], sys.version_info[1])


def link_files(src_root, dst_root, files):
for f in files:
src = join(THIS_DIR, src_root, f)
dst = join(PREFIX, dst_root, f)
dst_dir = dirname(dst)
if not isdir(dst_dir):
os.makedirs(dst_dir)
if exists(dst):
_unlink(dst)
_link(src, dst)
f = '%s/%s' % (dst_root, f)
FILES.append(f)
if f.endswith('.py'):
FILES.append(pyc_f(f))


def create_script(fn):
src = join(THIS_DIR, 'python-scripts', fn)
dst = join(BIN_DIR, fn)
if sys.platform == 'win32':
shutil.copyfile(src, dst + '-script.py')
FILES.append('Scripts/%s-script.py' % fn)
shutil.copyfile(join(THIS_DIR,
'cli-%d.exe' % (8 * tuple.__itemsize__)),
dst + '.exe')
FILES.append('Scripts/%s.exe' % fn)
else:
with open(src) as fi:
data = fi.read()
with open(dst, 'w') as fo:
fo.write('#!%s\n' % normpath(sys.executable))
fo.write(data)
os.chmod(dst, 0o755)
FILES.append('bin/%s' % fn)


def create_scripts(files):
if not files:
return
if not isdir(BIN_DIR):
os.mkdir(BIN_DIR)
for fn in files:
create_script(fn)


def main():
create_scripts(DATA['python-scripts'])
link_files('site-packages', SITE_PACKAGES, DATA['site-packages'])
link_files('Examples', 'Examples', DATA['Examples'])

with open(join(PREFIX, 'conda-meta',
'%s.files' % DATA['dist']), 'w') as fo:
for f in FILES:
fo.write('%s\n' % f)


if __name__ == '__main__':
main()
10 changes: 5 additions & 5 deletions conda_build/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def create_info_files(m, files, include_recipe=True):
files = [f.replace('\\', '/') for f in files]

with open(join(config.info_dir, 'files'), 'w') as fo:
if m.get_value('build/noarch') and 'py_' in m.dist():
if m.get_value('build/noarch_python'):
fo.write('\n')
else:
for f in files:
Expand All @@ -178,7 +178,7 @@ def create_info_files(m, files, include_recipe=True):
files_with_prefix = sorted(have_prefix_files(files))
binary_has_prefix_files = m.binary_has_prefix_files()
text_has_prefix_files = m.has_prefix_files()
if files_with_prefix:
if files_with_prefix and not m.get_value('build/noarch_python'):
auto_detect = m.get_value('build/detect_binary_files_with_prefix')
if sys.platform == 'win32':
# Paths on Windows can contain spaces, so we need to quote the
Expand Down Expand Up @@ -388,9 +388,9 @@ def build(m, get_src=True, verbose=True, post=None):
post_build(m, sorted(files2 - files1))
create_info_files(m, sorted(files2 - files1),
include_recipe=bool(m.path))
if m.get_value('build/noarch'):
import conda_build.noarch as noarch
noarch.transform(m, sorted(files2 - files1))
if m.get_value('build/noarch_python'):
import conda_build.noarch_python as noarch_python
noarch_python.transform(m, sorted(files2 - files1))

files3 = prefix_files()
fix_permissions(files3 - files1)
Expand Down
9 changes: 6 additions & 3 deletions conda_build/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def _git_clean(source_meta):
'patches'],
'build': ['number', 'string', 'entry_points', 'osx_is_app',
'features', 'track_features', 'preserve_egg_dir',
'no_link', 'binary_relocation', 'script', 'noarch',
'no_link', 'binary_relocation', 'script', 'noarch_python',
'has_prefix_files', 'binary_has_prefix_files',
'detect_binary_files_with_prefix', 'rpaths',
'always_include_files', ],
Expand Down Expand Up @@ -322,7 +322,8 @@ def ms_depends(self, typ='run'):
raise RuntimeError("Invalid package specification: %r" % spec)
for name, ver in name_ver_list:
if ms.name == name:
if ms.strictness != 1 or self.get_value('build/noarch'):
if (ms.strictness != 1 or
self.get_value('build/noarch_python')):
continue
str_ver = text_type(ver)
if '.' not in str_ver:
Expand Down Expand Up @@ -395,14 +396,16 @@ def info_index(self):
license = self.get_value('about/license'),
platform = cc.platform,
arch = cc.arch_name,
subdir = cc.subdir,
depends = sorted(ms.spec for ms in self.ms_depends())
)
if self.get_value('build/features'):
d['features'] = ' '.join(self.get_value('build/features'))
if self.get_value('build/track_features'):
d['track_features'] = ' '.join(self.get_value('build/track_features'))
if self.get_value('build/noarch'):
if self.get_value('build/noarch_python'):
d['platform'] = d['arch'] = None
d['subdir'] = 'noarch'
if self.is_app():
d.update(self.app_meta())
return d
Expand Down
91 changes: 0 additions & 91 deletions conda_build/noarch.py

This file was deleted.

108 changes: 108 additions & 0 deletions conda_build/noarch_python.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import os
import io
import sys
import json
import shutil
import locale
from os.path import basename, dirname, isdir, join

from conda_build.config import config
from conda_build.post import SHEBANG_PAT


def rewrite_script(fn):
src = join(config.build_prefix, 'bin', fn)
with io.open(src, encoding=locale.getpreferredencoding()) as fi:
try:
data = fi.read()
except UnicodeDecodeError: # file is binary
raise Exception("Binary: %s" % fn)
os.unlink(src)

m = SHEBANG_PAT.match(data)
if not (m and 'python' in m.group()):
raise Exception("No python shebang in: %s" % fn)
new_data = data[data.find('\n') + 1:]

dst_dir = join(config.build_prefix, 'python-scripts')
if not isdir(dst_dir):
os.makedirs(dst_dir)
with open(join(dst_dir, fn), 'w') as fo:
fo.write(new_data)


def handle_file(f, d):
path = join(config.build_prefix, f)
if f.endswith(('.egg-info', '.pyc')):
os.unlink(path)

elif f.endswith('.so'):
sys.exit("[noarch_python] Error: Shared object file found: %s" % f)

elif 'site-packages' in f:
nsp = join(config.build_prefix, 'site-packages')
if not isdir(nsp):
os.mkdir(nsp)
g = f[f.find('site-packages'):]
dst = join(config.build_prefix, g)
dst_dir = dirname(dst)
if not isdir(dst_dir):
os.makedirs(dst_dir)
os.rename(path, dst)
d['site-packages'].append(g[14:])

elif f.startswith('bin/'):
fn = basename(path)
rewrite_script(fn)
d['python-scripts'].append(fn)

elif f.startswith('Examples/'):
d['Examples'].append(f[9:])

else:
sys.exit("[noarch_python] Error: Don't know how to handle file: %s" % f)


def transform(m, files):
assert 'py_' in m.dist()
if sys.platform == 'win32':
sys.exit("[noarch_python] Error: Python noarch packages can currently "
"not be created on Windows systems.")

prefix = config.build_prefix
name = m.name()
with open(join(prefix, 'bin/.%s-pre-link.sh' % name), 'w') as fo:
fo.write('''\
#!/bin/bash
$PREFIX/bin/python $SOURCE_DIR/link.py
''')

scripts_dir = join(prefix, 'Scripts')
if not isdir(scripts_dir):
os.mkdir(scripts_dir)

with open(join(scripts_dir, '.%s-pre-link.bat' % name), 'w') as fo:
fo.write('''\
@echo off
"%PREFIX%\\python.exe" "%SOURCE_DIR%\\link.py"
''')

d = {'dist': m.dist(),
'site-packages': [],
'python-scripts': [],
'Examples': []}
for f in files:
handle_file(f, d)

this_dir = dirname(__file__)
if d['python-scripts']:
for fn in 'cli-32.exe', 'cli-64.exe':
shutil.copyfile(join(this_dir, fn), join(prefix, fn))

with open(join(this_dir, '_link.py')) as fi:
link_code = fi.read()
with open(join(prefix, 'link.py'), 'w') as fo:
fo.write('DATA = ')
json.dump(d, fo, indent=2, sort_keys=True)
fo.write('\n## END DATA\n\n')
fo.write(link_code)
2 changes: 1 addition & 1 deletion conda_build/tarcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def __init__(self, path):
self.name, self.version, self.build = self.dist.rsplit('-', 2)

def info_files(self):
if self.build.startswith('py_'):
if 'py_' in self.build:
return
lista = [p.strip().decode('utf-8') for p in
self.t.extractfile('info/files').readlines()]
Expand Down
7 changes: 7 additions & 0 deletions example_packages/noarch_python/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash

$PYTHON setup.py install

EXAMPLES=$PREFIX/Examples
mkdir $EXAMPLES
mv examples $EXAMPLES/bokeh