Merge lp:~sergiusens/snapcraft/collisions into lp:~snappy-dev/snapcraft/core

Proposed by Sergio Schvezov
Status: Merged
Approved by: Michael Vogt
Approved revision: 187
Merged at revision: 163
Proposed branch: lp:~sergiusens/snapcraft/collisions
Merge into: lp:~snappy-dev/snapcraft/core
Prerequisite: lp:~sergiusens/snapcraft/docs
Diff against target: 153 lines (+39/-18)
3 files modified
snapcraft/cmds.py (+10/-12)
snapcraft/plugin.py (+24/-4)
snapcraft/tests/test_cmds.py (+5/-2)
To merge this branch: bzr merge lp:~sergiusens/snapcraft/collisions
Reviewer Review Type Date Requested Status
Michael Vogt (community) Approve
Review via email: mp+270942@code.launchpad.net

Commit message

Collision logic updates with an introduction of _BUILTIN_OPTIONS so all parts have a certain set of options by default even if not declared.

Description of the change

This basically changes collisions to take into account filesets and also check during staging AND snapping.

To post a comment you must log in.
Revision history for this message
Michael Vogt (mvo) wrote :

Thanks, this looks good.

review: Approve
lp:~sergiusens/snapcraft/collisions updated
187. By Sergio Schvezov

keys with default values are better

Revision history for this message
Michael Vogt (mvo) wrote :

Nice!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'snapcraft/cmds.py'
2--- snapcraft/cmds.py 2015-09-14 16:21:34 +0000
3+++ snapcraft/cmds.py 2015-09-14 16:21:34 +0000
4@@ -223,24 +223,22 @@
5 qemu.kill()
6
7
8-def check_for_collisions(parts):
9- partsFiles = {}
10+def _check_for_collisions(parts, stage):
11+ parts_files = {}
12 for part in parts:
13 # Gather our own files up
14- partFiles = set()
15- for root, dirs, files in os.walk(part.installdir):
16- partFiles |= set([os.path.join(root, f) for f in files])
17- partFiles = set([os.path.relpath(x, part.installdir) for x in partFiles])
18+ fileset = getattr(part.code.options, stage, ['*']) or ['*']
19+ part_files, _ = snapcraft.plugin.migratable_filesets(fileset, part.installdir)
20
21 # Scan previous parts for collisions
22- for otherPartName in partsFiles:
23- common = partFiles & partsFiles[otherPartName]
24+ for other_part_name in parts_files:
25+ common = part_files & parts_files[other_part_name]
26 if common:
27- logger.error('Error: parts %s and %s have the following files in common:\n %s', otherPartName, part.names()[0], '\n '.join(sorted(common)))
28+ logger.error('Error: parts %s and %s have the following files in common:\n %s', other_part_name, part.names()[0], '\n '.join(sorted(common)))
29 return False
30
31 # And add our files to the list
32- partsFiles[part.names()[0]] = partFiles
33+ parts_files[part.names()[0]] = part_files
34
35 return True
36
37@@ -269,14 +267,14 @@
38
39 for part in config.all_parts:
40 for cmd in cmds:
41- if cmd == 'stage':
42+ if cmd is 'stage' or cmd is 'snap':
43 # This ends up running multiple times, as each part gets to its
44 # staging cmd. That's inefficient, but largely OK.
45 # FIXME: fix the above by iterating over cmds before iterating
46 # all_parts. But then we need to make sure we continue to handle
47 # cases like go, where you want go built before trying to pull
48 # a go project.
49- if not check_for_collisions(config.all_parts):
50+ if not _check_for_collisions(config.all_parts, cmd):
51 sys.exit(1)
52
53 common.env = config.build_env_for_part(part)
54
55=== modified file 'snapcraft/plugin.py'
56--- snapcraft/plugin.py 2015-09-14 16:21:34 +0000
57+++ snapcraft/plugin.py 2015-09-14 16:21:34 +0000
58@@ -30,6 +30,14 @@
59 logger = logging.getLogger(__name__)
60
61
62+_BUILTIN_OPTIONS = {
63+ 'filesets': {},
64+ 'snap': [],
65+ 'stage': [],
66+ 'stage-packages': [],
67+}
68+
69+
70 def is_local_plugin(name):
71 return name.startswith("x-")
72
73@@ -88,9 +96,16 @@
74 pass
75 options = Options()
76
77- for opt in self.config.get('options', []):
78+ plugin_options = self.config.get('options', {})
79+ # Let's append some mandatory options, but not .update() to not lose
80+ # original content
81+ for key in _BUILTIN_OPTIONS:
82+ if key not in plugin_options:
83+ plugin_options[key] = _BUILTIN_OPTIONS[key]
84+
85+ for opt in plugin_options:
86 attrname = opt.replace('-', '_')
87- opt_parameters = self.config['options'][opt] or {}
88+ opt_parameters = plugin_options[opt] or {}
89 if opt in properties:
90 setattr(options, attrname, properties[opt])
91 else:
92@@ -240,8 +255,7 @@
93 return part
94
95
96-def _migrate_files(fileset, srcdir, dstdir):
97- # validate
98+def migratable_filesets(fileset, srcdir):
99 includes, excludes = _get_file_list(fileset)
100
101 include_files = _generate_include_set(srcdir, includes)
102@@ -256,6 +270,12 @@
103 snap_dirs = set([x for x in snap_files if os.path.isdir(os.path.join(srcdir, x)) and not os.path.islink(os.path.join(srcdir, x))])
104 snap_files = snap_files - snap_dirs
105
106+ return snap_files, snap_dirs
107+
108+
109+def _migrate_files(fileset, srcdir, dstdir):
110+ snap_files, snap_dirs = migratable_filesets(fileset, srcdir)
111+
112 if snap_dirs:
113 common.run(['mkdir', '-p'] + list(snap_dirs), cwd=dstdir)
114 if snap_files:
115
116=== modified file 'snapcraft/tests/test_cmds.py'
117--- snapcraft/tests/test_cmds.py 2015-08-24 18:27:50 +0000
118+++ snapcraft/tests/test_cmds.py 2015-09-14 16:21:34 +0000
119@@ -39,12 +39,14 @@
120
121 part1 = mock.Mock()
122 part1.names.return_value = ['part1']
123+ part1.code.options.stage = ['*']
124 part1.installdir = tmpdir + '/install1'
125 os.makedirs(part1.installdir + '/a')
126 open(part1.installdir + '/a/1', mode='w').close()
127
128 part2 = mock.Mock()
129 part2.names.return_value = ['part2']
130+ part2.code.options.stage = ['*']
131 part2.installdir = tmpdir + '/install2'
132 os.makedirs(part2.installdir + '/a')
133 open(part2.installdir + '/1', mode='w').close()
134@@ -53,16 +55,17 @@
135
136 part3 = mock.Mock()
137 part3.names.return_value = ['part3']
138+ part3.code.options.stage = ['*']
139 part3.installdir = tmpdir + '/install3'
140 os.makedirs(part3.installdir + '/a')
141 os.makedirs(part3.installdir + '/b')
142 open(part3.installdir + '/1', mode='w').close()
143 open(part3.installdir + '/a/2', mode='w').close()
144
145- self.assertTrue(cmds.check_for_collisions([part1, part2]))
146+ self.assertTrue(cmds._check_for_collisions([part1, part2], 'stage'))
147 self.assertEqual('', fake_logger.output)
148
149- self.assertFalse(cmds.check_for_collisions([part1, part2, part3]))
150+ self.assertFalse(cmds._check_for_collisions([part1, part2, part3], 'stage'))
151 self.assertEqual(
152 'Error: parts part2 and part3 have the following files in common:\n'
153 ' 1\n'

Subscribers

People subscribed via source and target branches