Add NPM and CPAN entry points

parent 58e863c6
*******************
slapos.recipe.build
===================
*******************
.. contents::
Important notice
----------------
****************
This is totally experimental recipe for fully flexible software "build".
Examples
--------
********
Recipe to build the software.
......@@ -140,7 +143,7 @@ Which will link ${file:location}/bin/file to ${buildout:bin-directory}/bin/file
and ${file:location}/bin/file to ${buildout:bin-directory}/bin/anotherfile
Pure download
-------------
*************
::
......@@ -171,3 +174,95 @@ Notes
This recipe suffers from buildout download utility issue, which will do not
try to redownload resource with wrong md5sum.
slapos.recipe.build:cpan
************************
Downloads and installs perl modules using Comprehensive Perl Archive Network (cpan).
Examples
========
Basic example
-------------
Here is example to install one or several modules::
[buildout]
parts = perl-modules
[perl-modules]
recipe = slapos.recipe.build:cpan
modules =
Class::Date
Other::Module
# Optional argument specifying perl buildout part, if existing.
# If specified, recipe will use the perl installed by buildout.
# If not specified, will take the globally available perl executable.
perl = perl
Specific version
----------------
Note that cpan won't allow you to specify version and will always take latest
version available. To choose a specific version, you will need to specify
the full path in cpan like in ::
[buildout]
parts = perl-modules
[perl-modules]
recipe = slapos.recipe.build:cpan
modules =
D/DL/DLUX/Class-Date-1.1.10.tar.gz
perl = perl
Notes
=====
Currently, the modules will be installed in site-perl directory. Location of this
directory changes depending on the perl installation.
slapos.recipe.build:npm
***********************
Downloads and installs node.js packages using Node Package Manager (NPM).
Examples
========
Basic example
-------------
Here is example to install one or several modules::
[buildout]
parts = node-package
[node-package]
recipe = slapos.recipe.build:npm
modules =
colors
express
# Optional argument specifying perl buildout part, if existing.
# If specified, recipe will use the perl installed by buildout.
# If not specified, will take the globally available perl executable.
node = node-0.6
Specific version
----------------
[buildout]
parts = node-package
[node-package]
recipe = slapos.recipe.build:cpan
modules =
express==1.0.2
node = node-0.6
......@@ -30,7 +30,9 @@ setup(name=name,
'zc.buildout': [
'default = slapos.recipe.build:Script',
'cmmi = slapos.recipe.build:Cmmi',
'cpan = slapos.recipe.cpan:Cpan',
'download = slapos.recipe.download:Recipe',
'download-unpacked = slapos.recipe.downloadunpacked:Recipe'
'download-unpacked = slapos.recipe.downloadunpacked:Recipe',
'npm = slapos.recipe.npm:Npm',
]},
)
......@@ -382,29 +382,7 @@ class Cmmi(Script):
Compatibility on parameter level"""
script = """
if self.options['url']:
url = self.download(self.options['url'], self.options.get('md5sum'))
extract_dir = self.extract(url)
workdir = guessworkdir(extract_dir)
else:
workdir = self.options['path']
configure_command = self.options.get('configure-command')
if configure_command is None or configure_command.lower() == 'None':
configure_command = ["./configure", "--prefix=%(location)s"] + %(configure-options)r.split()
else:
configure_command = configure_command.split()
self.logger.info('Configuring with: %%r' %% ' '.join(configure_command))
self.applyPatchList(self.options.get('patches'), self.options.get('patch-options'), self.options.get('patch-binary'), workdir)
call(configure_command, cwd=workdir, env=env)
make_command = [self.options.get('make-binary', "make")]
make_options = self.options.get('make-options')
if make_options is not None:
make_command.extend(make_options.split())
self.logger.info('Building with %%r' %% ' '.join(make_command))
call(make_command, cwd=workdir, env=env)
make_command.append('install')
self.logger.info('Installing with %%r' %% ' '.join(make_command))
call(make_command + ['install'], cwd=workdir, env=env)
self._install()
"""
def __init__(self, buildout, name, options):
......@@ -414,4 +392,29 @@ call(make_command + ['install'], cwd=workdir, env=env)
if options['url'] and options['path']:
raise zc.buildout.UserError('You must use either "url" or "path", not both!')
if not (options['url'] or options['path']):
raise zc.buildout.UserError('You must provide either "url" or "path".')
\ No newline at end of file
raise zc.buildout.UserError('You must provide either "url" or "path".')
def _install(self):
if self.options['url']:
url = self.download(self.options['url'], self.options.get('md5sum'))
extract_dir = self.extract(url)
workdir = guessworkdir(extract_dir)
else:
workdir = self.options['path']
configure_command = self.options.get('configure-command')
if configure_command is None or configure_command.lower() == 'None':
configure_command = ["./configure", "--prefix=%(location)s"] + %(configure-options)r.split()
else:
configure_command = configure_command.split()
self.logger.info('Configuring with: %%r' %% ' '.join(configure_command))
self.applyPatchList(self.options.get('patches'), self.options.get('patch-options'), self.options.get('patch-binary'), workdir)
call(configure_command, cwd=workdir, env=env)
make_command = [self.options.get('make-binary', "make")]
make_options = self.options.get('make-options')
if make_options is not None:
make_command.extend(make_options.split())
self.logger.info('Building with %%r' %% ' '.join(make_command))
call(make_command, cwd=workdir, env=env)
make_command.append('install')
self.logger.info('Installing with %%r' %% ' '.join(make_command))
call(make_command + ['install'], cwd=workdir, env=env)
\ No newline at end of file
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import logging
import os
import subprocess
import zc.buildout
def createExecutable(name, content, mode=0755):
"""Create an executable with content
The parent directory should exists, else it would raise IOError"""
with open(name, 'w') as fileobject:
fileobject.write(content)
os.chmod(fileobject.name, mode)
return os.path.abspath(name)
def createWrapper(node, package):
"""Creates a node package wrapper"""
class Cpan(object):
"""Download and install locally node packages using cpan"""
def __init__(self, buildout, name, options):
self.cleanup_dir_list = []
self.buildout = buildout
self.name = name
self.logger = logging.getLogger(self.name)
self.options = {}
# Check for mandatory fields
if not options.get('modules'):
raise zc.buildout.UserError('No package specified in \'modules\' '
'parameter')
# Get variables
for k in ['location', 'modules', 'environment-section']:
self.options[k] = options.get(k, '').strip()
# Expose ${:location}
if self.options['location'] == '':
self.options['location'] = os.path.join(
buildout['buildout']['parts-directory'], self.name)
# Get perl binary. Mimic zc.recipe.egg behavior.
perl = options.get('perl')
if perl:
_cpan_executable = buildout[perl].get('perl_executable',
os.path.join(buildout[perl]['location'], 'bin', 'cpan'))
else:
self.logger.warn('Using system perl.')
_cpan_executable = 'cpan'
# Get list of packages to install
package_list = [
"%s" % s.strip()
for r in self.options['modules'].splitlines()
for s in r.split(' ')
if r.strip()]
self.popen_arguments = [_cpan_executable, 'install']
self.popen_arguments.extend(package_list)
def install(self):
# Create part directory
location = self.options.get('location')
if not os.path.isdir(location):
os.makedirs(location)
os.chdir(location)
environ = {}
# Set minimal working environment
environ['PATH'] = os.environ['PATH']
# Create cpan config directory in part directory
environ['HOME'] = self.options['location']
# Apply variables from defined environment (code from h.r.cmmi)
environment_section = self.options['environment-section']
if environment_section and environment_section in self.buildout:
# Use environment variables from the designated config section.
environ.update(self.buildout[environment_section])
for variable in self.options.get('environment', '').splitlines():
if variable.strip():
try:
key, value = variable.split('=', 1)
environ[key.strip()] = value
except ValueError:
raise zc.buildout.UserError('Invalid environment variable '
'definition: %s', variable)
# Extrapolate the environment variables using values from the current
# environment.
for key in environ:
environ[key] = environ[key] % os.environ
# Install packages
cpan_process = subprocess.Popen(self.popen_arguments, env=environ)
cpan_process.communicate()
if cpan_process.returncode is not 0:
raise zc.buildout.UserError('Failed to install perl modules.')
# Create wrappers
#for package in self.package_list:
# createExecutable()
# NODE_PATH=${:destination}/node_modules ${nodejs:node_location} ${:cloud9_js_location}
return [self.options['location']]
def update(self):
return None
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import logging
import os
import subprocess
import zc.buildout
def createExecutable(name, content, mode=0755):
"""Create an executable with content
The parent directory should exists, else it would raise IOError"""
with open(name, 'w') as fileobject:
fileobject.write(content)
os.chmod(fileobject.name, mode)
return os.path.abspath(name)
def createWrapper(node, package):
"""Creates a node package wrapper"""
class Npm(object):
"""Download and install locally node packages from node.js' NPM"""
def __init__(self, buildout, name, options):
self.cleanup_dir_list = []
self.buildout = buildout
self.name = name
self.logger = logging.getLogger(self.name)
self.options = {}
# Check for mandatory fields
if not options.get('packages'):
raise zc.buildout.UserError('No package specified in \'packages\' '
'parameter')
# Get variables
for k in ['location', 'packages', 'environment-section', 'node',
'environment']:
self.options[k] = options.get(k, '').strip()
# Expose ${:location}
if self.options['location'] == '':
self.options['location'] = options['location'] = os.path.join(
buildout['buildout']['parts-directory'], self.name)
# Get npm and node binaries. Mimic zc.recipe.egg behavior.
node = self.options.get('node')
if node:
_node_executable = buildout[node].get('node_executable',
os.path.join(buildout[node]['location'], 'bin', 'node'))
_npm_executable = buildout[node].get('npm_executable',
os.path.join(buildout[node]['location'], 'bin', 'npm'))
self.popen_arguments = [_node_executable, _npm_executable, 'install']
else:
self.logger.warn('Using system node.')
self.popen_arguments = ['npm', 'install']
# Get list of packages to install
self.package_list = [
"%s" % s.strip()
for r in self.options['packages'].splitlines()
for s in r.split(' ')
if r.strip()]
self.popen_arguments.extend(self.package_list)
def install(self):
# Create part directory
location = self.options.get('location')
if not os.path.isdir(location):
os.makedirs(location)
os.chdir(location)
environ = {}
# Set minimal working environment
environ['PATH'] = os.environ['PATH']
# Set NPM envvar to not share cache
environ['NPM_CONFIG_CACHE'] = os.path.join(location, 'cache')
# Arbitrary put packages installation to node_module directory
environ['NODE_PATH'] = os.path.join(location, 'node_modules')
# Override HOME so that npm won't create ~/.npm directory
environ['HOME'] = location
# Apply variables from defined environment (code from h.r.cmmi)
environment_section = self.options['environment-section']
if environment_section and environment_section in self.buildout:
# Use environment variables from the designated config section.
environ.update(self.buildout[environment_section])
for variable in self.options.get('environment', '').splitlines():
if variable.strip():
try:
key, value = variable.split('=', 1)
environ[key.strip()] = value
except ValueError:
raise zc.buildout.UserError('Invalid environment variable '
'definition: %s', variable)
# Extrapolate the environment variables using values from the current
# environment.
for key in environ:
environ[key] = environ[key] % os.environ
# Install packages
npm_process = subprocess.Popen(self.popen_arguments, env=environ)
npm_process.communicate()
if npm_process.returncode is not 0:
raise zc.buildout.UserError('Failed to install npm module(s).')
# Create wrappers
#for package in self.package_list:
# createExecutable()
# NODE_PATH=${:destination}/node_modules ${nodejs:node_location} ${:cloud9_js_location}
return [self.options['location']]
def update(self):
return None
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment