Support $SNAPCRAFT_STAGE for parts #270

Merged
merged 1 commit into from Jan 28, 2016
Jump to file or symbol
Failed to load files and symbols.
+261 −1
Split
@@ -127,6 +127,25 @@ will be built after `libpipeline`. Especially if you need specific
functionality during a build or as part of checks during the `stage` phase,
this will be handy.
+If any part built using the `after` keyword needs to explicitly access
+assets in the stage directory with configuration flags (e.g.; `configure`
@kyrofa

kyrofa Jan 28, 2016

Member

I don't think the semicolon is necessary here.

@sergiusens

sergiusens Jan 28, 2016

Collaborator

I picked this habit from scientific writing classes for my thesis.

Although they refer to using a comma instead of a semicolon, a separator is required http://english.stackexchange.com/questions/16172/should-i-always-use-a-comma-after-e-g-or-i-e

@kyrofa

kyrofa Jan 28, 2016

Member

Hahaha, okay you win! 😀

+in the case of autotools) it can use of the `SNAPCRAFT_STAGE` environment
+variable, like this:
+
+```yaml
+parts:
+ my-part:
+ plugin: autotools
+ source: .
+ configFlags:
+ - --with-swig $SNAPCRAFT_STAGE/swig
+ after:
+ - swig
+ swig:
+ plugin: autotools
+ source: ./swig
+```
+
### Re-using parts
With snapcraft we want to make it easy to learn from other app vendors and
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.2)
+project(simple-cmake)
+
+IF(NOT DEFINED DEP_DIR)
+ message(FATAL_ERROR "DEP_DIR is not defined.")
+ENDIF(NOT DEFINED DEP_DIR)
+
+# This is here to test $SNAPCRAFT_STAGE
+IF(NOT EXISTS "${DEP_DIR}/s")
+ message(FATAL_ERROR "${DEP_DIR}/s does not exist.")
+ENDIF(NOT EXISTS "${DEP_DIR}/s")
+
+file(WRITE my-file "stub file")
+install(FILES my-file DESTINATION share)
@@ -0,0 +1,19 @@
+name: test-package
+version: 0.1
+summary: try out $SNAPCRAFT_STAGE
+description: |
+ The cmake-project expects to have a copied directory in the stage directory
+ to consume during its build time.
+
+parts:
+ cmake-project:
+ plugin: cmake
+ source: .
+ configflags:
+ - -DDEP_DIR=$SNAPCRAFT_STAGE/copied
+ after:
+ - copy
+ copy:
+ plugin: copy
+ files:
+ copied: copied
@@ -86,3 +86,8 @@ def test_pull_with_circular_dependencies(self):
self.assertRaises(
subprocess.CalledProcessError,
self.run_snapcraft, 'pull', project_dir)
+
+ def test_snapcraft_stage_env_replacement(self):
+ project_dir = 'stage_env'
+
+ self.run_snapcraft('stage', project_dir)
@@ -32,6 +32,8 @@
repo,
)
+_SNAPCRAFT_STAGE = '$SNAPCRAFT_STAGE'
+
logger = logging.getLogger(__name__)
@@ -254,10 +256,21 @@ def _populate_options(options, properties, schema):
for key in schema_properties:
attr_name = key.replace('-', '_')
default_value = schema_properties[key].get('default')
- attr_value = properties.get(key, default_value)
+ attr_value = _expand_env(properties.get(key, default_value))
setattr(options, attr_name, attr_value)
+def _expand_env(attr):
+ if isinstance(attr, str) and _SNAPCRAFT_STAGE in attr:
+ return attr.replace(_SNAPCRAFT_STAGE, common.get_stagedir())
+ elif isinstance(attr, list) or isinstance(attr, tuple):
+ return [_expand_env(i) for i in attr]
+ elif isinstance(attr, dict):
+ return {k: _expand_env(attr[k]) for k in attr}
+
+ return attr
+
+
def _get_plugin(module):
for attr in vars(module).values():
if isinstance(attr, type) and issubclass(attr, snapcraft.BasePlugin):
@@ -355,3 +355,193 @@ def test_collisions_between_two_parts(self):
raised.exception.__str__(),
"Parts 'part2' and 'part3' have the following file paths in "
"common which have different contents:\n1\na/2")
+
+
+class StageEnvTestCase(tests.TestCase):
+
+ def test_string_replacements(self):
+ stagedir = common.get_stagedir()
+
+ replacements = (
+ (
+ 'no replacement',
+ 'snapcraft_stage/usr/bin',
+ 'snapcraft_stage/usr/bin',
+ ),
+ (
+ 'replaced start',
+ '$SNAPCRAFT_STAGE/usr/bin',
+ '{}/usr/bin'.format(stagedir),
+ ),
+ (
+ 'replaced between',
+ '--with-swig $SNAPCRAFT_STAGE/usr/swig',
+ '--with-swig {}/usr/swig'.format(stagedir),
+ ),
+ )
+
+ for test_name, subject, expected in replacements:
+ self.subTest(key=test_name)
+ self.assertEqual(pluginhandler._expand_env(subject), expected)
+
+ def test_lists_with_string_replacements(self):
+ stagedir = common.get_stagedir()
+
+ replacements = (
+ (
+ 'no replacement',
+ [
+ 'snapcraft_stage/usr/bin',
+ '/usr/bin',
+ ],
+ [
+ 'snapcraft_stage/usr/bin',
+ '/usr/bin',
+ ],
+ ),
+ (
+ 'replaced start',
+ [
+ '$SNAPCRAFT_STAGE/usr/bin',
+ '/usr/bin',
+ ],
+ [
+ '{}/usr/bin'.format(stagedir),
+ '/usr/bin',
+ ],
+ ),
+ (
+ 'replaced between',
+ [
+ '--without-python',
+ '--with-swig $SNAPCRAFT_STAGE/usr/swig',
+ ],
+ [
+ '--without-python',
+ '--with-swig {}/usr/swig'.format(stagedir),
+ ],
+ ),
+ )
+
+ for test_name, subject, expected in replacements:
+ self.subTest(key=test_name)
+ self.assertEqual(pluginhandler._expand_env(subject), expected)
+
+ def test_tuples_with_string_replacements(self):
+ stagedir = common.get_stagedir()
+
+ replacements = (
+ (
+ 'no replacement',
+ (
+ 'snapcraft_stage/usr/bin',
+ '/usr/bin',
+ ),
+ [
+ 'snapcraft_stage/usr/bin',
+ '/usr/bin',
+ ],
+ ),
+ (
+ 'replaced start',
+ (
+ '$SNAPCRAFT_STAGE/usr/bin',
+ '/usr/bin',
+ ),
+ [
+ '{}/usr/bin'.format(stagedir),
+ '/usr/bin',
+ ],
+ ),
+ (
+ 'replaced between',
+ (
+ '--without-python',
+ '--with-swig $SNAPCRAFT_STAGE/usr/swig',
+ ),
+ [
+ '--without-python',
+ '--with-swig {}/usr/swig'.format(stagedir),
+ ],
+ ),
+ )
+
+ for test_name, subject, expected in replacements:
+ self.subTest(key=test_name)
+ self.assertEqual(pluginhandler._expand_env(subject), expected)
+
+ def test_dict_with_string_replacements(self):
+ stagedir = common.get_stagedir()
+
+ replacements = (
+ (
+ 'no replacement',
+ {
+ '1': 'snapcraft_stage/usr/bin',
+ '2': '/usr/bin',
+ },
+ {
+ '1': 'snapcraft_stage/usr/bin',
+ '2': '/usr/bin',
+ },
+ ),
+ (
+ 'replaced start',
+ {
+ '1': '$SNAPCRAFT_STAGE/usr/bin',
+ '2': '/usr/bin',
+ },
+ {
+ '1': '{}/usr/bin'.format(stagedir),
+ '2': '/usr/bin',
+ },
+ ),
+ (
+ 'replaced between',
+ {
+ '1': '--without-python',
+ '2': '--with-swig $SNAPCRAFT_STAGE/usr/swig',
+ },
+ {
+ '1': '--without-python',
+ '2': '--with-swig {}/usr/swig'.format(stagedir),
+ },
+ ),
+ )
+
+ for test_name, subject, expected in replacements:
+ self.subTest(key=test_name)
+ self.assertEqual(pluginhandler._expand_env(subject), expected)
+
+ def test_string_replacement_with_complex_data(self):
+ stagedir = common.get_stagedir()
+
+ subject = {
+ 'filesets': {
+ 'files': [
+ 'somefile',
+ '$SNAPCRAFT_STAGE/file1',
+ 'SNAPCRAFT_STAGE/really',
+ ]
+ },
+ 'configFlags': [
+ '--with-python',
+ '--with-swig $SNAPCRAFT_STAGE/swig',
+ ],
+ }
+
+ expected = {
+ 'filesets': {
+ 'files': [
+ 'somefile',
+ '{}/file1'.format(stagedir),
+ 'SNAPCRAFT_STAGE/really',
+ ]
+ },
+ 'configFlags': [
+ '--with-python',
+ '--with-swig {}/swig'.format(stagedir),
+ ],
+ }
+
+ self.assertEqual(pluginhandler._expand_env(subject), expected)