Add a phase for creating extra ISOs
Signed-off-by: Lubomír Sedlář <lsedlar@redhat.com>
This commit is contained in:
parent
4544b454f8
commit
b2f995d516
@ -107,6 +107,7 @@ def run(config, topdir, has_old):
|
||||
pungi.phases.OSTreePhase(compose),
|
||||
pungi.phases.ProductimgPhase(compose, pkgset_phase),
|
||||
pungi.phases.CreateisoPhase(compose, buildinstall_phase),
|
||||
pungi.phases.ExtraIsosPhase(compose),
|
||||
pungi.phases.LiveImagesPhase(compose),
|
||||
pungi.phases.LiveMediaPhase(compose),
|
||||
pungi.phases.ImageBuildPhase(compose),
|
||||
|
@ -300,6 +300,7 @@ def run_compose(compose, create_latest_link=True, latest_link_status=None):
|
||||
ostree_phase = pungi.phases.OSTreePhase(compose)
|
||||
productimg_phase = pungi.phases.ProductimgPhase(compose, pkgset_phase)
|
||||
createiso_phase = pungi.phases.CreateisoPhase(compose, buildinstall_phase)
|
||||
extra_isos_phase = pungi.phases.ExtraIsosPhase(compose)
|
||||
liveimages_phase = pungi.phases.LiveImagesPhase(compose)
|
||||
livemedia_phase = pungi.phases.LiveMediaPhase(compose)
|
||||
image_build_phase = pungi.phases.ImageBuildPhase(compose)
|
||||
@ -313,7 +314,7 @@ def run_compose(compose, create_latest_link=True, latest_link_status=None):
|
||||
extrafiles_phase, createiso_phase, liveimages_phase,
|
||||
livemedia_phase, image_build_phase, image_checksum_phase,
|
||||
test_phase, ostree_phase, ostree_installer_phase,
|
||||
osbs_phase):
|
||||
extra_isos_phase, osbs_phase):
|
||||
if phase.skip():
|
||||
continue
|
||||
try:
|
||||
@ -402,6 +403,7 @@ def run_compose(compose, create_latest_link=True, latest_link_status=None):
|
||||
# Start all phases for image artifacts
|
||||
compose_images_schema = (
|
||||
createiso_phase,
|
||||
extra_isos_phase,
|
||||
liveimages_phase,
|
||||
image_build_phase,
|
||||
livemedia_phase,
|
||||
|
BIN
doc/_static/phases.png
vendored
BIN
doc/_static/phases.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
300
doc/_static/phases.svg
vendored
300
doc/_static/phases.svg
vendored
@ -9,12 +9,12 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="839.33331"
|
||||
height="220.33334"
|
||||
viewBox="0 0 839.33334 220.33335"
|
||||
width="771.66455"
|
||||
height="221.50018"
|
||||
viewBox="0 0 771.66458 221.50019"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="phases.svg"
|
||||
inkscape:export-filename="/home/lsedlar/repos/pungi/doc/_static/phases.png"
|
||||
inkscape:export-xdpi="90"
|
||||
@ -26,21 +26,25 @@
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="1"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.6532468"
|
||||
inkscape:cx="337.4932"
|
||||
inkscape:cy="70.825454"
|
||||
inkscape:zoom="1.169022"
|
||||
inkscape:cx="396.63448"
|
||||
inkscape:cy="97.894202"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1020"
|
||||
inkscape:window-height="1016"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="31"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
units="px"
|
||||
inkscape:document-rotation="0"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true" />
|
||||
inkscape:guide-bbox="true"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<marker
|
||||
@ -67,12 +71,12 @@
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="matrix(1.066667,0,0,1.066667,0,-902.18643)"
|
||||
transform="matrix(1.066667,0,0,1.066667,-2.473231,-910.85239)"
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Vrstva 1">
|
||||
@ -115,8 +119,7 @@
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="556.95709"
|
||||
y="971.54041"
|
||||
id="text3384-0"
|
||||
sodipodi:linespacing="0%"><tspan
|
||||
id="text3384-0"><tspan
|
||||
y="971.54041"
|
||||
x="556.95709"
|
||||
sodipodi:role="line"
|
||||
@ -139,8 +142,7 @@
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="557.61566"
|
||||
y="971.33813"
|
||||
id="text3396"
|
||||
sodipodi:linespacing="0%"><tspan
|
||||
id="text3396"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3398"
|
||||
x="557.61566"
|
||||
@ -162,8 +164,7 @@
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="6.2600794"
|
||||
y="891.1604"
|
||||
id="text3356"
|
||||
sodipodi:linespacing="0%"><tspan
|
||||
id="text3356"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3358"
|
||||
x="6.2600794"
|
||||
@ -173,7 +174,7 @@
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3642"
|
||||
d="m 100.90864,859.8891 553.31842,0"
|
||||
d="M 100.90864,859.8891 H 654.22706"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.17466855px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)" />
|
||||
<g
|
||||
id="g241"
|
||||
@ -187,7 +188,6 @@
|
||||
y="400.8551"
|
||||
transform="matrix(0,1,1,0,0,0)" />
|
||||
<text
|
||||
sodipodi:linespacing="0%"
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="403.15945"
|
||||
@ -212,7 +212,6 @@
|
||||
id="rect3342"
|
||||
style="fill:#fcaf3e;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<text
|
||||
sodipodi:linespacing="0%"
|
||||
id="text3364"
|
||||
y="891.06732"
|
||||
x="105.76799"
|
||||
@ -235,7 +234,6 @@
|
||||
id="rect3344"
|
||||
style="fill:#729fcf;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<text
|
||||
sodipodi:linespacing="0%"
|
||||
id="text3368"
|
||||
y="923.25934"
|
||||
x="106.1384"
|
||||
@ -261,7 +259,6 @@
|
||||
transform="matrix(0,1,1,0,0,0)" />
|
||||
</g>
|
||||
<text
|
||||
sodipodi:linespacing="0%"
|
||||
id="text3372"
|
||||
y="923.25934"
|
||||
x="165.23042"
|
||||
@ -284,7 +281,6 @@
|
||||
id="rect3348"
|
||||
style="fill:#e9b96e;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<text
|
||||
sodipodi:linespacing="0%"
|
||||
id="text3376"
|
||||
y="921.86945"
|
||||
x="243.95874"
|
||||
@ -308,7 +304,6 @@
|
||||
id="rect3350-3"
|
||||
style="fill:#729fcf;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<text
|
||||
sodipodi:linespacing="0%"
|
||||
id="text3380-2"
|
||||
y="840.3219"
|
||||
x="256.90588"
|
||||
@ -324,7 +319,7 @@
|
||||
transform="translate(-328.39105,-85.517823)"
|
||||
id="g288">
|
||||
<g
|
||||
transform="translate(0.56706579,0)"
|
||||
transform="translate(0.56706579)"
|
||||
id="g3653">
|
||||
<rect
|
||||
style="fill:#fcaf3e;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
@ -335,141 +330,156 @@
|
||||
y="490.33765"
|
||||
transform="matrix(0,1,1,0,0,0)" />
|
||||
<text
|
||||
sodipodi:linespacing="0%"
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.99999714px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="492.642"
|
||||
y="1039.4121"
|
||||
id="text3430"><tspan
|
||||
id="tspan283"
|
||||
sodipodi:role="line"
|
||||
x="492.642"
|
||||
y="1039.4121">OSTreeInstaller</tspan></text>
|
||||
y="1039.4121"
|
||||
style="font-size:11.99999714px;line-height:0">OSTreeInstaller</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g236"
|
||||
transform="translate(-60.108974,42.1407)">
|
||||
<g
|
||||
transform="translate(88.832932,-122.61379)"
|
||||
id="g3458">
|
||||
<rect
|
||||
transform="matrix(0,1,1,0,0,0)"
|
||||
style="fill:#edd400;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
id="rect3338"
|
||||
width="26.295755"
|
||||
height="102.36562"
|
||||
x="953.49097"
|
||||
y="420.13605" />
|
||||
<text
|
||||
id="text3384"
|
||||
y="971.54041"
|
||||
id="g3458"
|
||||
transform="translate(28.723958,-80.473035)">
|
||||
<rect
|
||||
y="420.13605"
|
||||
x="953.49097"
|
||||
height="102.36562"
|
||||
width="26.295755"
|
||||
id="rect3338"
|
||||
style="fill:#edd400;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
transform="matrix(0,1,1,0,0,0)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="422.99252"
|
||||
y="971.54041"
|
||||
id="text3384"><tspan
|
||||
style="font-size:13.14787769px;line-height:1.25"
|
||||
sodipodi:role="line"
|
||||
id="tspan3386"
|
||||
x="422.99252"
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
xml:space="preserve"
|
||||
sodipodi:linespacing="0%"><tspan
|
||||
y="971.54041"
|
||||
x="422.99252"
|
||||
id="tspan3386"
|
||||
sodipodi:role="line"
|
||||
style="font-size:13.14787769px;line-height:1.25">Createiso</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
id="g3453"
|
||||
transform="translate(88.576485,-121.89312)">
|
||||
<rect
|
||||
transform="matrix(0,1,1,0,0,0)"
|
||||
y="420.39337"
|
||||
x="989.65247"
|
||||
height="101.85102"
|
||||
width="26.295755"
|
||||
id="rect3352"
|
||||
style="fill:#73d216;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<text
|
||||
id="text3388"
|
||||
y="1006.4276"
|
||||
y="971.54041">Createiso</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(28.467511,-84.181232)"
|
||||
id="g3453">
|
||||
<rect
|
||||
style="fill:#73d216;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
id="rect3352"
|
||||
width="26.295755"
|
||||
height="101.85102"
|
||||
x="989.65247"
|
||||
y="420.39337"
|
||||
transform="matrix(0,1,1,0,0,0)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="422.69772"
|
||||
y="1006.4276"
|
||||
id="text3388"><tspan
|
||||
style="font-size:13.14787769px;line-height:1.25"
|
||||
sodipodi:role="line"
|
||||
id="tspan3390"
|
||||
x="422.69772"
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
xml:space="preserve"
|
||||
sodipodi:linespacing="0%"><tspan
|
||||
y="1006.4276"
|
||||
x="422.69772"
|
||||
id="tspan3390"
|
||||
sodipodi:role="line"
|
||||
style="font-size:13.14787769px;line-height:1.25">LiveImages</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
id="g3448"
|
||||
transform="translate(88.576485,-121.42489)">
|
||||
<rect
|
||||
transform="matrix(0,1,1,0,0,0)"
|
||||
y="420.39337"
|
||||
x="1026.0664"
|
||||
height="101.85102"
|
||||
width="26.295755"
|
||||
id="rect3354"
|
||||
style="fill:#f57900;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<text
|
||||
id="text3392"
|
||||
y="1042.8416"
|
||||
y="1006.4276">LiveImages</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(28.467511,-88.141877)"
|
||||
id="g3448">
|
||||
<rect
|
||||
style="fill:#f57900;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
id="rect3354"
|
||||
width="26.295755"
|
||||
height="101.85102"
|
||||
x="1026.0664"
|
||||
y="420.39337"
|
||||
transform="matrix(0,1,1,0,0,0)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="422.69772"
|
||||
y="1042.8416"
|
||||
id="text3392"><tspan
|
||||
style="font-size:13.14787769px;line-height:1.25"
|
||||
sodipodi:role="line"
|
||||
id="tspan3394"
|
||||
x="422.69772"
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
xml:space="preserve"
|
||||
sodipodi:linespacing="0%"><tspan
|
||||
y="1042.8416"
|
||||
x="422.69772"
|
||||
id="tspan3394"
|
||||
sodipodi:role="line"
|
||||
style="font-size:13.14787769px;line-height:1.25">ImageBuild</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
id="g3443"
|
||||
transform="translate(87.869393,-121.31225)">
|
||||
<rect
|
||||
style="fill:#edd400;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
id="rect3422"
|
||||
width="26.295755"
|
||||
height="101.85102"
|
||||
x="1062.8359"
|
||||
y="421.10046"
|
||||
transform="matrix(0,1,1,0,0,0)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="423.40482"
|
||||
y="1042.8416">ImageBuild</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(27.760419,-92.458101)"
|
||||
id="g3443">
|
||||
<rect
|
||||
transform="matrix(0,1,1,0,0,0)"
|
||||
y="421.10046"
|
||||
x="1062.8359"
|
||||
height="101.85102"
|
||||
width="26.295755"
|
||||
id="rect3422"
|
||||
style="fill:#edd400;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<text
|
||||
id="text3424"
|
||||
y="1079.6111"
|
||||
x="423.40482"
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:13.14787769px;line-height:1.25"
|
||||
y="1079.6111"
|
||||
id="text3424"
|
||||
sodipodi:linespacing="0%"><tspan
|
||||
id="tspan3434"
|
||||
sodipodi:role="line"
|
||||
x="423.40482"
|
||||
y="1079.6111"
|
||||
style="font-size:13.14787769px;line-height:1.25">LiveMedia</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(18.63221,-71.202583)"
|
||||
id="g306">
|
||||
<rect
|
||||
style="fill:#c17d11;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
id="rect290"
|
||||
width="26.295755"
|
||||
height="101.85102"
|
||||
x="1048.9327"
|
||||
y="490.33765"
|
||||
transform="matrix(0,1,1,0,0,0)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.99999714px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="423.40482"
|
||||
sodipodi:role="line"
|
||||
id="tspan3434">LiveMedia</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
id="g306"
|
||||
transform="translate(-41.476764,-46.1016)">
|
||||
<rect
|
||||
transform="matrix(0,1,1,0,0,0)"
|
||||
y="490.33765"
|
||||
x="1048.9327"
|
||||
height="101.85102"
|
||||
width="26.295755"
|
||||
id="rect290"
|
||||
style="fill:#c17d11;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<text
|
||||
id="text294"
|
||||
y="1065.7078"
|
||||
x="492.642"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:11.99999714px;line-height:0"
|
||||
id="tspan301"
|
||||
sodipodi:role="line"
|
||||
x="492.642"
|
||||
y="1065.7078"
|
||||
id="text294"
|
||||
sodipodi:linespacing="0%"><tspan
|
||||
y="1065.7078"
|
||||
x="492.642"
|
||||
sodipodi:role="line"
|
||||
id="tspan301">OSBS</tspan></text>
|
||||
</g>
|
||||
y="1065.7078">OSBS</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
id="g3819"
|
||||
transform="translate(0,-16.949078)">
|
||||
<rect
|
||||
transform="matrix(0,1,1,0,0,0)"
|
||||
y="448.86087"
|
||||
x="1052.2335"
|
||||
height="101.85102"
|
||||
width="26.295755"
|
||||
id="rect3801"
|
||||
style="fill:#73d216;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<text
|
||||
id="text3805"
|
||||
y="1069.0087"
|
||||
x="451.16522"
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
xml:space="preserve"><tspan
|
||||
id="tspan3812"
|
||||
y="1069.0087"
|
||||
x="451.16522"
|
||||
sodipodi:role="line"
|
||||
style="font-size:13.14787769px;line-height:1.25">ExtraIsos</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
@ -1450,6 +1450,85 @@ Example config
|
||||
}
|
||||
|
||||
|
||||
Extra ISOs
|
||||
==========
|
||||
|
||||
Create an ISO image that contains packages from multiple variants. Such ISO
|
||||
always belongs to one variant, and will be stored in ISO directory of that
|
||||
variant.
|
||||
|
||||
The ISO will be bootable if buildinstall phase runs for the parent variant. It
|
||||
will reuse boot configuration from that variant.
|
||||
|
||||
**extra_isos**
|
||||
(*dict*) -- a mapping from variant UID regex to a list of configuration
|
||||
blocks.
|
||||
|
||||
* ``include_variants`` -- (*list*) list of variant UIDs from which content
|
||||
should be added to the ISO; the variant of this image is added
|
||||
automatically.
|
||||
|
||||
Rest of configuration keys is optional.
|
||||
|
||||
* ``filename`` -- (*str*) template for naming the image. In addition to the
|
||||
regular placeholders ``filename`` is available with the name generated
|
||||
using ``image_name_format`` option.
|
||||
|
||||
* ``volid`` -- (*str*) template for generating volume ID. Again ``volid``
|
||||
placeholder can be used similarly as for file name. This can also be a
|
||||
list of templates that will be tried sequentially until one generates a
|
||||
volume ID that fits into 32 character limit.
|
||||
|
||||
* ``extra_files`` -- (*list*) a list of :ref:`scm_dict <scm_support>`
|
||||
objects. These files will be put in the top level directory of the image.
|
||||
|
||||
* ``arches`` -- (*list*) a list of architectures for which to build this
|
||||
image. By default all arches from the variant will be used. This option
|
||||
can be used to limit them.
|
||||
|
||||
* ``failable_arches`` -- (*list*) a list of architectures for which the
|
||||
image can fail to be generated and not fail the entire compose.
|
||||
|
||||
* ``skip_src`` -- (*bool*) allows to disable creating an image with source
|
||||
packages.
|
||||
|
||||
Example config
|
||||
--------------
|
||||
::
|
||||
|
||||
extra_isos = {
|
||||
'Server': [{
|
||||
# Will generate foo-DP-1.0-20180510.t.43-Server-x86_64-dvd1.iso
|
||||
'filename': 'foo-{filename}',
|
||||
'volid': 'foo-{arch}',
|
||||
|
||||
'extra_files': [{
|
||||
'scm': 'git',
|
||||
'repo': 'https://pagure.io/pungi.git',
|
||||
'file': 'setup.py'
|
||||
}],
|
||||
|
||||
'include_variants': ['Client']
|
||||
}]
|
||||
}
|
||||
# This should create image with the following layout:
|
||||
# .
|
||||
# ├── Client
|
||||
# │ ├── Packages
|
||||
# │ │ ├── a
|
||||
# │ │ └── b
|
||||
# │ └── repodata
|
||||
# ├── Server
|
||||
# │ ├── extra_files.json # extra file from Server
|
||||
# │ ├── LICENSE # extra file from Server
|
||||
# │ ├── Packages
|
||||
# │ │ ├── a
|
||||
# │ │ └── b
|
||||
# │ └── repodata
|
||||
# └── setup.py
|
||||
|
||||
|
||||
|
||||
Media Checksums Settings
|
||||
========================
|
||||
|
||||
|
@ -99,6 +99,15 @@ packages fit on a single image.
|
||||
|
||||
There can also be images with source repositories. These are never bootable.
|
||||
|
||||
ExtraIsos
|
||||
---------
|
||||
|
||||
This phase is very similar to ``createiso``, except it combines content from
|
||||
multiple variants onto a single image. Packages, repodata and extra files from
|
||||
each configured variant are put into a subdirectory. Additional extra files can
|
||||
be put into top level of the image. The image will be bootable if the main
|
||||
variant is bootable.
|
||||
|
||||
LiveImages, LiveMedia
|
||||
---------------------
|
||||
|
||||
|
@ -863,6 +863,47 @@ def make_schema():
|
||||
"$ref": "#/definitions/list_of_strings"
|
||||
}),
|
||||
|
||||
"extra_isos": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
# Warning: this pattern is a variant uid regex, but the
|
||||
# format does not let us validate it as there is no regular
|
||||
# expression to describe all regular expressions.
|
||||
".+": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"include_variants": {"$ref": "#/definitions/strings"},
|
||||
"extra_files": _one_or_list({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"scm": {"type": "string"},
|
||||
"repo": {"type": "string"},
|
||||
"branch": {"$ref": "#/definitions/optional_string"},
|
||||
"file": {"$ref": "#/definitions/strings"},
|
||||
"target": {"type": "string"},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
}),
|
||||
"filename": {"type": "string"},
|
||||
"volid": {"$ref": "#/definitions/strings"},
|
||||
"arches": {"$ref": "#/definitions/list_of_strings"},
|
||||
"failable_arches": {
|
||||
"$ref": "#/definitions/list_of_strings"
|
||||
},
|
||||
"skip_src": {
|
||||
"type": "boolean",
|
||||
"default": False,
|
||||
},
|
||||
},
|
||||
"required": ["include_variants"],
|
||||
"additionalProperties": False
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"live_media": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
|
@ -264,6 +264,18 @@ class WorkPaths(object):
|
||||
makedirs(path)
|
||||
return path
|
||||
|
||||
def extra_iso_extra_files_dir(self, arch, variant, create_dir=True):
|
||||
"""
|
||||
Examples:
|
||||
work/x86_64/Server/extra-iso-extra-files
|
||||
"""
|
||||
if arch == "global":
|
||||
raise RuntimeError("Global extra files dir makes no sense.")
|
||||
path = os.path.join(self.topdir(arch, create_dir=create_dir), variant.uid, "extra-iso-extra-files")
|
||||
if create_dir:
|
||||
makedirs(path)
|
||||
return path
|
||||
|
||||
def repo_package_list(self, arch, variant, pkg_type=None, create_dir=True):
|
||||
"""
|
||||
Examples:
|
||||
|
@ -25,6 +25,7 @@ from .product_img import ProductimgPhase # noqa
|
||||
from .buildinstall import BuildinstallPhase # noqa
|
||||
from .extra_files import ExtraFilesPhase # noqa
|
||||
from .createiso import CreateisoPhase # noqa
|
||||
from .extra_isos import ExtraIsosPhase # noqa
|
||||
from .live_images import LiveImagesPhase # noqa
|
||||
from .image_build import ImageBuildPhase # noqa
|
||||
from .test import TestPhase # noqa
|
||||
|
@ -395,13 +395,7 @@ def prepare_iso(compose, arch, variant, disc_num=1, disc_count=None, split_iso_d
|
||||
if i in ti.checksums.checksums.keys():
|
||||
del ti.checksums.checksums[i]
|
||||
|
||||
# make a copy of isolinux/isolinux.bin, images/boot.img - they get modified when mkisofs is called
|
||||
for i in ("isolinux/isolinux.bin", "images/boot.img"):
|
||||
src_path = os.path.join(tree_dir, i)
|
||||
dst_path = os.path.join(iso_dir, i)
|
||||
if os.path.exists(src_path):
|
||||
makedirs(os.path.dirname(dst_path))
|
||||
shutil.copy2(src_path, dst_path)
|
||||
copy_boot_images(tree_dir, iso_dir)
|
||||
|
||||
if disc_count > 1:
|
||||
# remove repodata/repomd.xml from checksums, create a new one later
|
||||
@ -454,3 +448,15 @@ def prepare_iso(compose, arch, variant, disc_num=1, disc_count=None, split_iso_d
|
||||
gp = "%s-graft-points" % iso_dir
|
||||
iso.write_graft_points(gp, data, exclude=["*/lost+found", "*/boot.iso"])
|
||||
return gp
|
||||
|
||||
|
||||
def copy_boot_images(src, dest):
|
||||
"""When mkisofs is called it tries to modify isolinux/isolinux.bin and
|
||||
images/boot.img. Therefore we need to make copies of them.
|
||||
"""
|
||||
for i in ("isolinux/isolinux.bin", "images/boot.img"):
|
||||
src_path = os.path.join(src, i)
|
||||
dst_path = os.path.join(dest, i)
|
||||
if os.path.exists(src_path):
|
||||
makedirs(os.path.dirname(dst_path))
|
||||
shutil.copy2(src_path, dst_path)
|
||||
|
201
pungi/phases/extra_isos.py
Normal file
201
pungi/phases/extra_isos.py
Normal file
@ -0,0 +1,201 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
# 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; version 2 of the License.
|
||||
#
|
||||
# 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 Library General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, see <https://gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
|
||||
from kobo.shortcuts import force_list
|
||||
from kobo.threads import ThreadPool, WorkerThread
|
||||
|
||||
from pungi import createiso
|
||||
from pungi.phases.base import ConfigGuardedPhase, PhaseBase, PhaseLoggerMixin
|
||||
from pungi.phases.createiso import (add_iso_to_metadata, copy_boot_images,
|
||||
run_createiso_command)
|
||||
from pungi.util import failable, get_format_substs, get_variant_data, get_volid
|
||||
from pungi.wrappers import iso
|
||||
from pungi.wrappers.scm import get_dir_from_scm, get_file_from_scm
|
||||
|
||||
|
||||
class ExtraIsosPhase(PhaseLoggerMixin, ConfigGuardedPhase, PhaseBase):
|
||||
name = "extra_isos"
|
||||
|
||||
def __init__(self, compose):
|
||||
super(ExtraIsosPhase, self).__init__(compose)
|
||||
self.pool = ThreadPool(logger=self.logger)
|
||||
|
||||
def validate(self):
|
||||
for variant in self.compose.get_variants(types=['variant']):
|
||||
for config in get_variant_data(self.compose.conf, self.name, variant):
|
||||
extra_arches = set(config.get('arches', [])) - set(variant.arches)
|
||||
if extra_arches:
|
||||
self.compose.log_warning(
|
||||
'Extra iso config for %s mentions non-existing arches: %s'
|
||||
% (variant, ', '.join(sorted(extra_arches))))
|
||||
|
||||
def run(self):
|
||||
commands = []
|
||||
|
||||
for variant in self.compose.get_variants(types=['variant']):
|
||||
for config in get_variant_data(self.compose.conf, self.name, variant):
|
||||
arches = set(variant.arches)
|
||||
if config.get('arches'):
|
||||
arches &= set(config['arches'])
|
||||
if not config['skip_src']:
|
||||
arches.add('src')
|
||||
for arch in sorted(arches):
|
||||
commands.append((config, variant, arch))
|
||||
|
||||
for (config, variant, arch) in commands:
|
||||
self.pool.add(ExtraIsosThread(self.pool))
|
||||
self.pool.queue_put((self.compose, config, variant, arch))
|
||||
|
||||
self.pool.start()
|
||||
|
||||
|
||||
class ExtraIsosThread(WorkerThread):
|
||||
def process(self, item, num):
|
||||
self.num = num
|
||||
compose, config, variant, arch = item
|
||||
can_fail = arch in config.get('failable_arches', [])
|
||||
with failable(compose, can_fail, variant, arch, 'extra_iso', logger=self.pool._logger):
|
||||
self.worker(compose, config, variant, arch)
|
||||
|
||||
def worker(self, compose, config, variant, arch):
|
||||
filename = get_filename(compose, variant, arch, config.get('filename'))
|
||||
volid = get_volume_id(compose, variant, arch, config.get('volid', []))
|
||||
iso_dir = compose.paths.compose.iso_dir(arch, variant)
|
||||
iso_path = os.path.join(iso_dir, filename)
|
||||
|
||||
msg = "Creating ISO (arch: %s, variant: %s): %s" % (arch, variant, filename)
|
||||
self.pool.log_info("[BEGIN] %s" % msg)
|
||||
|
||||
get_extra_files(compose, variant, arch, config.get('extra_files', []))
|
||||
|
||||
bootable = arch != "src" and compose.conf['bootable']
|
||||
|
||||
graft_points = get_iso_contents(compose, variant, arch,
|
||||
config['include_variants'],
|
||||
filename, bootable)
|
||||
|
||||
opts = createiso.CreateIsoOpts(
|
||||
output_dir=iso_dir,
|
||||
iso_name=filename,
|
||||
volid=volid,
|
||||
graft_points=graft_points,
|
||||
arch=arch,
|
||||
supported=compose.supported,
|
||||
)
|
||||
|
||||
if bootable:
|
||||
opts = opts._replace(buildinstall_method=compose.conf['buildinstall_method'])
|
||||
|
||||
script_file = os.path.join(compose.paths.work.tmp_dir(arch, variant),
|
||||
'extraiso-%s.sh' % filename)
|
||||
with open(script_file, 'w') as f:
|
||||
createiso.write_script(opts, f)
|
||||
|
||||
run_createiso_command(compose.conf["runroot"], self.num, compose, bootable, arch,
|
||||
['bash', script_file], [compose.topdir],
|
||||
log_file=compose.paths.log.log_file(
|
||||
arch, "extraiso-%s" % os.path.basename(iso_path)),
|
||||
with_jigdo=False)
|
||||
|
||||
add_iso_to_metadata(compose, variant, arch, iso_path, bootable, 1, 1)
|
||||
|
||||
self.pool.log_info("[DONE ] %s" % msg)
|
||||
|
||||
|
||||
def get_extra_files(compose, variant, arch, extra_files):
|
||||
"""Clone the configured files into a directory from where they can be
|
||||
included in the ISO.
|
||||
"""
|
||||
extra_files_dir = compose.paths.work.extra_iso_extra_files_dir(arch, variant)
|
||||
for scm_dict in extra_files:
|
||||
getter = get_file_from_scm if 'file' in scm_dict else get_dir_from_scm
|
||||
target_path = os.path.join(extra_files_dir, scm_dict.get('target', '').lstrip('/'))
|
||||
getter(scm_dict, target_path, logger=compose._logger)
|
||||
|
||||
|
||||
def get_iso_contents(compose, variant, arch, include_variants, filename, bootable):
|
||||
"""Find all files that should be on the ISO. For bootable image we start
|
||||
with the boot configuration. Then for each variant we add packages,
|
||||
repodata and extra files. Finally we add top-level extra files.
|
||||
"""
|
||||
iso_dir = compose.paths.work.iso_dir(arch, filename)
|
||||
|
||||
files = {}
|
||||
if bootable:
|
||||
buildinstall_dir = compose.paths.work.buildinstall_dir(arch, create_dir=False)
|
||||
if compose.conf['buildinstall_method'] == 'lorax':
|
||||
buildinstall_dir = os.path.join(buildinstall_dir, variant.uid)
|
||||
|
||||
copy_boot_images(buildinstall_dir, iso_dir)
|
||||
files = iso.get_graft_points([buildinstall_dir, iso_dir])
|
||||
|
||||
variants = [variant.uid] + include_variants
|
||||
for variant_uid in variants:
|
||||
var = compose.all_variants[variant_uid]
|
||||
|
||||
# Get packages...
|
||||
package_dir = compose.paths.compose.packages(arch, var)
|
||||
for k, v in iso.get_graft_points([package_dir]).items():
|
||||
files[os.path.join(var.uid, 'Packages', k)] = v
|
||||
|
||||
# Get repodata...
|
||||
tree_dir = compose.paths.compose.repository(arch, var)
|
||||
repo_dir = os.path.join(tree_dir, 'repodata')
|
||||
for k, v in iso.get_graft_points([repo_dir]).items():
|
||||
files[os.path.join(var.uid, 'repodata', k)] = v
|
||||
|
||||
# Get extra files...
|
||||
extra_files_dir = compose.paths.work.extra_files_dir(arch, var)
|
||||
for k, v in iso.get_graft_points([extra_files_dir]).items():
|
||||
files[os.path.join(var.uid, k)] = v
|
||||
|
||||
# Add extra files specific for the ISO
|
||||
extra_files_dir = compose.paths.work.extra_iso_extra_files_dir(arch, variant)
|
||||
files.update(iso.get_graft_points([extra_files_dir]))
|
||||
|
||||
gp = "%s-graft-points" % iso_dir
|
||||
iso.write_graft_points(gp, files, exclude=["*/lost+found", "*/boot.iso"])
|
||||
return gp
|
||||
|
||||
|
||||
def get_filename(compose, variant, arch, format):
|
||||
disc_type = compose.conf['disc_types'].get('dvd', 'dvd')
|
||||
base_filename = compose.get_image_name(
|
||||
arch, variant, disc_type=disc_type, disc_num=1)
|
||||
if not format:
|
||||
return base_filename
|
||||
kwargs = {
|
||||
'arch': arch,
|
||||
'disc_type': disc_type,
|
||||
'disc_num': 1,
|
||||
'suffix': '.iso',
|
||||
'filename': base_filename,
|
||||
'variant': variant,
|
||||
}
|
||||
args = get_format_substs(compose, **kwargs)
|
||||
try:
|
||||
return (format % args).format(**args)
|
||||
except KeyError as err:
|
||||
raise RuntimeError('Failed to create image name: unknown format element: %s' % err)
|
||||
|
||||
|
||||
def get_volume_id(compose, variant, arch, formats):
|
||||
disc_type = compose.conf['disc_types'].get('dvd', 'dvd')
|
||||
# Get volume ID for regular ISO so that we can substitute it in.
|
||||
volid = get_volid(compose, arch, variant, disc_type=disc_type)
|
||||
return get_volid(compose, arch, variant, disc_type=disc_type,
|
||||
formats=force_list(formats), volid=volid)
|
@ -330,7 +330,8 @@ def _apply_substitutions(compose, volid):
|
||||
return volid
|
||||
|
||||
|
||||
def get_volid(compose, arch, variant=None, escape_spaces=False, disc_type=False):
|
||||
def get_volid(compose, arch, variant=None, escape_spaces=False, disc_type=False,
|
||||
formats=None, **kwargs):
|
||||
"""Get ISO volume ID for arch and variant"""
|
||||
if variant and variant.type == "addon":
|
||||
# addons are part of parent variant media
|
||||
@ -359,9 +360,10 @@ def get_volid(compose, arch, variant=None, escape_spaces=False, disc_type=False)
|
||||
all_products = layered_products + products
|
||||
else:
|
||||
all_products = products
|
||||
formats = formats or all_products
|
||||
|
||||
tried = set()
|
||||
for i in all_products:
|
||||
for i in formats:
|
||||
if not variant_uid and "%(variant)s" in i:
|
||||
continue
|
||||
try:
|
||||
@ -372,7 +374,8 @@ def get_volid(compose, arch, variant=None, escape_spaces=False, disc_type=False)
|
||||
arch=arch,
|
||||
disc_type=disc_type or '',
|
||||
base_product_short=base_product_short,
|
||||
base_product_version=base_product_version)
|
||||
base_product_version=base_product_version,
|
||||
**kwargs)
|
||||
volid = (i % args).format(**args)
|
||||
except KeyError as err:
|
||||
raise RuntimeError('Failed to create volume id: unknown format element: %s' % err)
|
||||
|
@ -114,4 +114,11 @@ createiso_skip = [
|
||||
}),
|
||||
]
|
||||
|
||||
extra_isos = {
|
||||
'^Server$': [{
|
||||
'include_variants': ['Client']
|
||||
'filename': 'extra-{filename}',
|
||||
}]
|
||||
}
|
||||
|
||||
create_jigdo = False
|
||||
|
529
tests/test_extra_isos_phase.py
Normal file
529
tests/test_extra_isos_phase.py
Normal file
@ -0,0 +1,529 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
try:
|
||||
import unittest2 as unittest
|
||||
except ImportError:
|
||||
import unittest
|
||||
import mock
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
||||
|
||||
from tests import helpers
|
||||
from pungi.phases import extra_isos
|
||||
|
||||
|
||||
@mock.patch('pungi.phases.extra_isos.ThreadPool')
|
||||
class ExtraIsosPhaseTest(helpers.PungiTestCase):
|
||||
|
||||
def test_logs_extra_arches(self, ThreadPool):
|
||||
cfg = {
|
||||
'include_variants': ['Client'],
|
||||
'arches': ['x86_64', 'ppc64le', 'aarch64'],
|
||||
}
|
||||
compose = helpers.DummyCompose(self.topdir, {
|
||||
'extra_isos': {
|
||||
'^Server$': [cfg]
|
||||
}
|
||||
})
|
||||
|
||||
phase = extra_isos.ExtraIsosPhase(compose)
|
||||
phase.validate()
|
||||
|
||||
self.assertEqual(len(compose.log_warning.call_args_list), 1)
|
||||
|
||||
def test_one_task_for_each_arch(self, ThreadPool):
|
||||
cfg = {
|
||||
'include_variants': ['Client'],
|
||||
}
|
||||
compose = helpers.DummyCompose(self.topdir, {
|
||||
'extra_isos': {
|
||||
'^Server$': [cfg]
|
||||
}
|
||||
})
|
||||
|
||||
phase = extra_isos.ExtraIsosPhase(compose)
|
||||
phase.run()
|
||||
|
||||
self.assertEqual(len(ThreadPool.return_value.add.call_args_list), 3)
|
||||
self.assertItemsEqual(
|
||||
ThreadPool.return_value.queue_put.call_args_list,
|
||||
[mock.call((compose, cfg, compose.variants['Server'], 'x86_64')),
|
||||
mock.call((compose, cfg, compose.variants['Server'], 'amd64')),
|
||||
mock.call((compose, cfg, compose.variants['Server'], 'src'))]
|
||||
)
|
||||
|
||||
def test_filter_arches(self, ThreadPool):
|
||||
cfg = {
|
||||
'include_variants': ['Client'],
|
||||
'arches': ['x86_64'],
|
||||
}
|
||||
compose = helpers.DummyCompose(self.topdir, {
|
||||
'extra_isos': {
|
||||
'^Server$': [cfg]
|
||||
}
|
||||
})
|
||||
|
||||
phase = extra_isos.ExtraIsosPhase(compose)
|
||||
phase.run()
|
||||
|
||||
self.assertEqual(len(ThreadPool.return_value.add.call_args_list), 2)
|
||||
self.assertItemsEqual(
|
||||
ThreadPool.return_value.queue_put.call_args_list,
|
||||
[mock.call((compose, cfg, compose.variants['Server'], 'x86_64')),
|
||||
mock.call((compose, cfg, compose.variants['Server'], 'src'))]
|
||||
)
|
||||
|
||||
def test_skip_source(self, ThreadPool):
|
||||
cfg = {
|
||||
'include_variants': ['Client'],
|
||||
'skip_src': True,
|
||||
}
|
||||
compose = helpers.DummyCompose(self.topdir, {
|
||||
'extra_isos': {
|
||||
'^Server$': [cfg]
|
||||
}
|
||||
})
|
||||
|
||||
phase = extra_isos.ExtraIsosPhase(compose)
|
||||
phase.run()
|
||||
|
||||
self.assertEqual(len(ThreadPool.return_value.add.call_args_list), 2)
|
||||
self.assertItemsEqual(
|
||||
ThreadPool.return_value.queue_put.call_args_list,
|
||||
[mock.call((compose, cfg, compose.variants['Server'], 'x86_64')),
|
||||
mock.call((compose, cfg, compose.variants['Server'], 'amd64'))]
|
||||
)
|
||||
|
||||
|
||||
@mock.patch('pungi.phases.extra_isos.get_volume_id')
|
||||
@mock.patch('pungi.phases.extra_isos.get_filename')
|
||||
@mock.patch('pungi.phases.extra_isos.get_iso_contents')
|
||||
@mock.patch('pungi.phases.extra_isos.get_extra_files')
|
||||
@mock.patch('pungi.phases.extra_isos.run_createiso_command')
|
||||
@mock.patch('pungi.phases.extra_isos.add_iso_to_metadata')
|
||||
class ExtraIsosThreadTest(helpers.PungiTestCase):
|
||||
|
||||
def test_binary_bootable_image(self, aitm, rcc, gef, gic, gfn, gvi):
|
||||
compose = helpers.DummyCompose(self.topdir, {
|
||||
'bootable': True,
|
||||
'buildinstall_method': 'lorax'
|
||||
})
|
||||
server = compose.variants['Server']
|
||||
cfg = {
|
||||
'include_variants': ['Client'],
|
||||
}
|
||||
|
||||
gfn.return_value = 'my.iso'
|
||||
gvi.return_value = 'my volume id'
|
||||
gic.return_value = '/tmp/iso-graft-points'
|
||||
|
||||
t = extra_isos.ExtraIsosThread(mock.Mock())
|
||||
with mock.patch('time.sleep'):
|
||||
t.process((compose, cfg, server, 'x86_64'), 1)
|
||||
|
||||
self.assertEqual(gfn.call_args_list,
|
||||
[mock.call(compose, server, 'x86_64', None)])
|
||||
self.assertEqual(gvi.call_args_list,
|
||||
[mock.call(compose, server, 'x86_64', [])])
|
||||
self.assertEqual(gef.call_args_list,
|
||||
[mock.call(compose, server, 'x86_64', [])])
|
||||
self.assertEqual(gic.call_args_list,
|
||||
[mock.call(compose, server, 'x86_64', ['Client'], 'my.iso', True)])
|
||||
self.assertEqual(
|
||||
rcc.call_args_list,
|
||||
[mock.call(False, 1, compose, True, 'x86_64',
|
||||
['bash', os.path.join(self.topdir, 'work/x86_64/tmp-Server/extraiso-my.iso.sh')],
|
||||
[self.topdir],
|
||||
log_file=os.path.join(self.topdir, 'logs/x86_64/extraiso-my.iso.x86_64.log'),
|
||||
with_jigdo=False)]
|
||||
|
||||
)
|
||||
self.assertEqual(
|
||||
aitm.call_args_list,
|
||||
[mock.call(compose, server, 'x86_64',
|
||||
os.path.join(self.topdir, 'compose/Server/x86_64/iso/my.iso'),
|
||||
True, 1, 1)]
|
||||
)
|
||||
|
||||
def test_binary_image_custom_naming(self, aitm, rcc, gef, gic, gfn, gvi):
|
||||
compose = helpers.DummyCompose(self.topdir, {})
|
||||
server = compose.variants['Server']
|
||||
cfg = {
|
||||
'include_variants': ['Client'],
|
||||
'filename': 'fn',
|
||||
'volid': ['v1', 'v2'],
|
||||
}
|
||||
|
||||
gfn.return_value = 'my.iso'
|
||||
gvi.return_value = 'my volume id'
|
||||
gic.return_value = '/tmp/iso-graft-points'
|
||||
|
||||
t = extra_isos.ExtraIsosThread(mock.Mock())
|
||||
with mock.patch('time.sleep'):
|
||||
t.process((compose, cfg, server, 'x86_64'), 1)
|
||||
|
||||
self.assertEqual(gfn.call_args_list,
|
||||
[mock.call(compose, server, 'x86_64', 'fn')])
|
||||
self.assertEqual(gvi.call_args_list,
|
||||
[mock.call(compose, server, 'x86_64', ['v1', 'v2'])])
|
||||
self.assertEqual(gef.call_args_list,
|
||||
[mock.call(compose, server, 'x86_64', [])])
|
||||
self.assertEqual(gic.call_args_list,
|
||||
[mock.call(compose, server, 'x86_64', ['Client'], 'my.iso', False)])
|
||||
self.assertEqual(
|
||||
rcc.call_args_list,
|
||||
[mock.call(False, 1, compose, False, 'x86_64',
|
||||
['bash', os.path.join(self.topdir, 'work/x86_64/tmp-Server/extraiso-my.iso.sh')],
|
||||
[self.topdir],
|
||||
log_file=os.path.join(self.topdir, 'logs/x86_64/extraiso-my.iso.x86_64.log'),
|
||||
with_jigdo=False)]
|
||||
|
||||
)
|
||||
self.assertEqual(
|
||||
aitm.call_args_list,
|
||||
[mock.call(compose, server, 'x86_64',
|
||||
os.path.join(self.topdir, 'compose/Server/x86_64/iso/my.iso'),
|
||||
False, 1, 1)]
|
||||
)
|
||||
|
||||
def test_source_is_not_bootable(self, aitm, rcc, gef, gic, gfn, gvi):
|
||||
compose = helpers.DummyCompose(self.topdir, {
|
||||
'bootable': True,
|
||||
'buildinstall_method': 'lorax'
|
||||
})
|
||||
server = compose.variants['Server']
|
||||
cfg = {
|
||||
'include_variants': ['Client'],
|
||||
}
|
||||
|
||||
gfn.return_value = 'my.iso'
|
||||
gvi.return_value = 'my volume id'
|
||||
gic.return_value = '/tmp/iso-graft-points'
|
||||
|
||||
t = extra_isos.ExtraIsosThread(mock.Mock())
|
||||
with mock.patch('time.sleep'):
|
||||
t.process((compose, cfg, server, 'src'), 1)
|
||||
|
||||
self.assertEqual(gfn.call_args_list,
|
||||
[mock.call(compose, server, 'src', None)])
|
||||
self.assertEqual(gvi.call_args_list,
|
||||
[mock.call(compose, server, 'src', [])])
|
||||
self.assertEqual(gef.call_args_list,
|
||||
[mock.call(compose, server, 'src', [])])
|
||||
self.assertEqual(gic.call_args_list,
|
||||
[mock.call(compose, server, 'src', ['Client'], 'my.iso', False)])
|
||||
self.assertEqual(
|
||||
rcc.call_args_list,
|
||||
[mock.call(False, 1, compose, False, 'src',
|
||||
['bash', os.path.join(self.topdir, 'work/src/tmp-Server/extraiso-my.iso.sh')],
|
||||
[self.topdir],
|
||||
log_file=os.path.join(self.topdir, 'logs/src/extraiso-my.iso.src.log'),
|
||||
with_jigdo=False)]
|
||||
|
||||
)
|
||||
self.assertEqual(
|
||||
aitm.call_args_list,
|
||||
[mock.call(compose, server, 'src',
|
||||
os.path.join(self.topdir, 'compose/Server/source/iso/my.iso'),
|
||||
False, 1, 1)]
|
||||
)
|
||||
|
||||
def test_failable_failed(self, aitm, rcc, gef, gic, gfn, gvi):
|
||||
compose = helpers.DummyCompose(self.topdir, {})
|
||||
server = compose.variants['Server']
|
||||
cfg = {
|
||||
'include_variants': ['Client'],
|
||||
'failable_arches': ['x86_64'],
|
||||
}
|
||||
|
||||
gfn.return_value = 'my.iso'
|
||||
gvi.return_value = 'my volume id'
|
||||
gic.return_value = '/tmp/iso-graft-points'
|
||||
rcc.side_effect = helpers.mk_boom()
|
||||
|
||||
t = extra_isos.ExtraIsosThread(mock.Mock())
|
||||
with mock.patch('time.sleep'):
|
||||
t.process((compose, cfg, server, 'x86_64'), 1)
|
||||
|
||||
self.assertEqual(aitm.call_args_list, [])
|
||||
|
||||
def test_non_failable_failed(self, aitm, rcc, gef, gic, gfn, gvi):
|
||||
compose = helpers.DummyCompose(self.topdir, {})
|
||||
server = compose.variants['Server']
|
||||
cfg = {
|
||||
'include_variants': ['Client'],
|
||||
}
|
||||
|
||||
gfn.return_value = 'my.iso'
|
||||
gvi.return_value = 'my volume id'
|
||||
gic.return_value = '/tmp/iso-graft-points'
|
||||
rcc.side_effect = helpers.mk_boom(RuntimeError)
|
||||
|
||||
t = extra_isos.ExtraIsosThread(mock.Mock())
|
||||
with self.assertRaises(RuntimeError):
|
||||
with mock.patch('time.sleep'):
|
||||
t.process((compose, cfg, server, 'x86_64'), 1)
|
||||
|
||||
self.assertEqual(aitm.call_args_list, [])
|
||||
|
||||
|
||||
@mock.patch('pungi.phases.extra_isos.get_file_from_scm')
|
||||
@mock.patch('pungi.phases.extra_isos.get_dir_from_scm')
|
||||
class GetExtraFilesTest(helpers.PungiTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(GetExtraFilesTest, self).setUp()
|
||||
self.compose = helpers.DummyCompose(self.topdir, {})
|
||||
self.variant = self.compose.variants['Server']
|
||||
self.arch = 'x86_64'
|
||||
|
||||
def test_no_config(self, get_dir, get_file):
|
||||
extra_isos.get_extra_files(self.compose, self.variant, self.arch, [])
|
||||
|
||||
self.assertEqual(get_dir.call_args_list, [])
|
||||
self.assertEqual(get_file.call_args_list, [])
|
||||
|
||||
def test_get_file(self, get_dir, get_file):
|
||||
cfg = {
|
||||
'scm': 'git',
|
||||
'repo': 'https://pagure.io/pungi.git',
|
||||
'file': 'GPL',
|
||||
'target': 'legalese',
|
||||
}
|
||||
extra_isos.get_extra_files(self.compose, self.variant, self.arch, [cfg])
|
||||
|
||||
self.assertEqual(get_dir.call_args_list, [])
|
||||
self.assertEqual(get_file.call_args_list,
|
||||
[mock.call(cfg,
|
||||
os.path.join(self.topdir, 'work',
|
||||
self.arch, self.variant.uid,
|
||||
'extra-iso-extra-files/legalese'),
|
||||
logger=self.compose._logger)])
|
||||
|
||||
def test_get_dir(self, get_dir, get_file):
|
||||
cfg = {
|
||||
'scm': 'git',
|
||||
'repo': 'https://pagure.io/pungi.git',
|
||||
'dir': 'docs',
|
||||
'target': 'foo',
|
||||
}
|
||||
extra_isos.get_extra_files(self.compose, self.variant, self.arch, [cfg])
|
||||
|
||||
self.assertEqual(get_file.call_args_list, [])
|
||||
self.assertEqual(get_dir.call_args_list,
|
||||
[mock.call(cfg,
|
||||
os.path.join(self.topdir, 'work',
|
||||
self.arch, self.variant.uid,
|
||||
'extra-iso-extra-files/foo'),
|
||||
logger=self.compose._logger)])
|
||||
|
||||
|
||||
@mock.patch('pungi.wrappers.iso.write_graft_points')
|
||||
@mock.patch('pungi.wrappers.iso.get_graft_points')
|
||||
class GetIsoContentsTest(helpers.PungiTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(GetIsoContentsTest, self).setUp()
|
||||
self.compose = helpers.DummyCompose(self.topdir, {})
|
||||
self.variant = self.compose.variants['Server']
|
||||
|
||||
def test_non_bootable_binary(self, ggp, wgp):
|
||||
gp = {
|
||||
'compose/Client/x86_64/os/Packages': {'f/foo.rpm': '/mnt/f/foo.rpm'},
|
||||
'compose/Client/x86_64/os/repodata': {'primary.xml': '/mnt/repodata/primary.xml'},
|
||||
'compose/Server/x86_64/os/Packages': {'b/bar.rpm': '/mnt/b/bar.rpm'},
|
||||
'compose/Server/x86_64/os/repodata': {'repomd.xml': '/mnt/repodata/repomd.xml'},
|
||||
'work/x86_64/Client/extra-files': {'GPL': '/mnt/GPL'},
|
||||
'work/x86_64/Server/extra-files': {'AUTHORS': '/mnt/AUTHORS'},
|
||||
'work/x86_64/Server/extra-iso-extra-files': {'EULA': '/mnt/EULA'},
|
||||
}
|
||||
|
||||
ggp.side_effect = lambda x: gp[x[0][len(self.topdir) + 1:]]
|
||||
gp_file = os.path.join(self.topdir, 'work/x86_64/iso/my.iso-graft-points')
|
||||
|
||||
self.assertEqual(
|
||||
extra_isos.get_iso_contents(self.compose, self.variant, 'x86_64',
|
||||
['Client'], 'my.iso', False),
|
||||
gp_file
|
||||
)
|
||||
|
||||
expected = {
|
||||
'Client/GPL': '/mnt/GPL',
|
||||
'Client/Packages/f/foo.rpm': '/mnt/f/foo.rpm',
|
||||
'Client/repodata/primary.xml': '/mnt/repodata/primary.xml',
|
||||
'EULA': '/mnt/EULA',
|
||||
'Server/AUTHORS': '/mnt/AUTHORS',
|
||||
'Server/Packages/b/bar.rpm': '/mnt/b/bar.rpm',
|
||||
'Server/repodata/repomd.xml': '/mnt/repodata/repomd.xml',
|
||||
}
|
||||
|
||||
self.assertItemsEqual(
|
||||
ggp.call_args_list,
|
||||
[mock.call([os.path.join(self.topdir, x)]) for x in gp]
|
||||
)
|
||||
self.assertEqual(len(wgp.call_args_list), 1)
|
||||
self.assertEqual(wgp.call_args_list[0][0][0], gp_file)
|
||||
self.assertDictEqual(dict(wgp.call_args_list[0][0][1]), expected)
|
||||
self.assertEqual(wgp.call_args_list[0][1], {'exclude': ["*/lost+found", "*/boot.iso"]})
|
||||
|
||||
def test_source(self, ggp, wgp):
|
||||
gp = {
|
||||
'compose/Client/source/tree/Packages': {'f/foo.rpm': '/mnt/f/foo.rpm'},
|
||||
'compose/Client/source/tree/repodata': {'primary.xml': '/mnt/repodata/primary.xml'},
|
||||
'compose/Server/source/tree/Packages': {'b/bar.rpm': '/mnt/b/bar.rpm'},
|
||||
'compose/Server/source/tree/repodata': {'repomd.xml': '/mnt/repodata/repomd.xml'},
|
||||
'work/src/Client/extra-files': {'GPL': '/mnt/GPL'},
|
||||
'work/src/Server/extra-files': {'AUTHORS': '/mnt/AUTHORS'},
|
||||
'work/src/Server/extra-iso-extra-files': {'EULA': '/mnt/EULA'},
|
||||
}
|
||||
|
||||
ggp.side_effect = lambda x: gp[x[0][len(self.topdir) + 1:]]
|
||||
gp_file = os.path.join(self.topdir, 'work/src/iso/my.iso-graft-points')
|
||||
|
||||
self.assertEqual(
|
||||
extra_isos.get_iso_contents(self.compose, self.variant, 'src',
|
||||
['Client'], 'my.iso', False),
|
||||
gp_file
|
||||
)
|
||||
|
||||
expected = {
|
||||
'Client/GPL': '/mnt/GPL',
|
||||
'Client/Packages/f/foo.rpm': '/mnt/f/foo.rpm',
|
||||
'Client/repodata/primary.xml': '/mnt/repodata/primary.xml',
|
||||
'EULA': '/mnt/EULA',
|
||||
'Server/AUTHORS': '/mnt/AUTHORS',
|
||||
'Server/Packages/b/bar.rpm': '/mnt/b/bar.rpm',
|
||||
'Server/repodata/repomd.xml': '/mnt/repodata/repomd.xml',
|
||||
}
|
||||
|
||||
self.assertItemsEqual(
|
||||
ggp.call_args_list,
|
||||
[mock.call([os.path.join(self.topdir, x)]) for x in gp]
|
||||
)
|
||||
self.assertEqual(len(wgp.call_args_list), 1)
|
||||
self.assertEqual(wgp.call_args_list[0][0][0], gp_file)
|
||||
self.assertDictEqual(dict(wgp.call_args_list[0][0][1]), expected)
|
||||
self.assertEqual(wgp.call_args_list[0][1], {'exclude': ["*/lost+found", "*/boot.iso"]})
|
||||
|
||||
def test_bootable(self, ggp, wgp):
|
||||
self.compose.conf['buildinstall_method'] = 'lorax'
|
||||
|
||||
bi_dir = os.path.join(self.topdir, 'work/x86_64/buildinstall/Server')
|
||||
iso_dir = os.path.join(self.topdir, 'work/x86_64/iso/my.iso')
|
||||
helpers.touch(os.path.join(bi_dir, 'isolinux/isolinux.bin'))
|
||||
helpers.touch(os.path.join(bi_dir, 'images/boot.img'))
|
||||
|
||||
gp = {
|
||||
'compose/Client/x86_64/os/Packages': {'f/foo.rpm': '/mnt/f/foo.rpm'},
|
||||
'compose/Client/x86_64/os/repodata': {'primary.xml': '/mnt/repodata/primary.xml'},
|
||||
'compose/Server/x86_64/os/Packages': {'b/bar.rpm': '/mnt/b/bar.rpm'},
|
||||
'compose/Server/x86_64/os/repodata': {'repomd.xml': '/mnt/repodata/repomd.xml'},
|
||||
'work/x86_64/Client/extra-files': {'GPL': '/mnt/GPL'},
|
||||
'work/x86_64/Server/extra-files': {'AUTHORS': '/mnt/AUTHORS'},
|
||||
'work/x86_64/Server/extra-iso-extra-files': {'EULA': '/mnt/EULA'},
|
||||
}
|
||||
bi_gp = {
|
||||
'isolinux/isolinux.bin': os.path.join(iso_dir, 'isolinux/isolinux.bin'),
|
||||
'images/boot.img': os.path.join(iso_dir, 'images/boot.img'),
|
||||
}
|
||||
|
||||
ggp.side_effect = lambda x: gp[x[0][len(self.topdir) + 1:]] if len(x) == 1 else bi_gp
|
||||
gp_file = os.path.join(self.topdir, 'work/x86_64/iso/my.iso-graft-points')
|
||||
|
||||
self.assertEqual(
|
||||
extra_isos.get_iso_contents(self.compose, self.variant, 'x86_64',
|
||||
['Client'], 'my.iso', True),
|
||||
gp_file
|
||||
)
|
||||
|
||||
self.maxDiff = None
|
||||
|
||||
expected = {
|
||||
'Client/GPL': '/mnt/GPL',
|
||||
'Client/Packages/f/foo.rpm': '/mnt/f/foo.rpm',
|
||||
'Client/repodata/primary.xml': '/mnt/repodata/primary.xml',
|
||||
'EULA': '/mnt/EULA',
|
||||
'Server/AUTHORS': '/mnt/AUTHORS',
|
||||
'Server/Packages/b/bar.rpm': '/mnt/b/bar.rpm',
|
||||
'Server/repodata/repomd.xml': '/mnt/repodata/repomd.xml',
|
||||
'isolinux/isolinux.bin': os.path.join(iso_dir, 'isolinux/isolinux.bin'),
|
||||
'images/boot.img': os.path.join(iso_dir, 'images/boot.img'),
|
||||
}
|
||||
|
||||
self.assertItemsEqual(
|
||||
ggp.call_args_list,
|
||||
[mock.call([os.path.join(self.topdir, x)]) for x in gp] + [mock.call([bi_dir, iso_dir])]
|
||||
)
|
||||
self.assertEqual(len(wgp.call_args_list), 1)
|
||||
self.assertEqual(wgp.call_args_list[0][0][0], gp_file)
|
||||
self.assertDictEqual(dict(wgp.call_args_list[0][0][1]), expected)
|
||||
self.assertEqual(wgp.call_args_list[0][1], {'exclude': ["*/lost+found", "*/boot.iso"]})
|
||||
|
||||
# Check files were copied to temp directory
|
||||
self.assertTrue(os.path.exists(os.path.join(iso_dir, 'isolinux/isolinux.bin')))
|
||||
self.assertTrue(os.path.exists(os.path.join(iso_dir, 'images/boot.img')))
|
||||
|
||||
|
||||
class GetFilenameTest(helpers.PungiTestCase):
|
||||
def test_use_original_name(self):
|
||||
compose = helpers.DummyCompose(self.topdir, {})
|
||||
|
||||
fn = extra_isos.get_filename(compose, compose.variants['Server'], 'x86_64',
|
||||
'foo-{variant}-{arch}-{filename}')
|
||||
|
||||
self.assertEqual(fn, 'foo-Server-x86_64-image-name')
|
||||
|
||||
def test_use_default_without_format(self):
|
||||
compose = helpers.DummyCompose(self.topdir, {})
|
||||
|
||||
fn = extra_isos.get_filename(compose, compose.variants['Server'], 'x86_64',
|
||||
None)
|
||||
|
||||
self.assertEqual(fn, 'image-name')
|
||||
|
||||
def test_reports_unknown_placeholder(self):
|
||||
compose = helpers.DummyCompose(self.topdir, {})
|
||||
|
||||
with self.assertRaises(RuntimeError) as ctx:
|
||||
extra_isos.get_filename(compose, compose.variants['Server'], 'x86_64',
|
||||
'foo-{boom}')
|
||||
|
||||
self.assertIn('boom', str(ctx.exception))
|
||||
|
||||
|
||||
class GetVolumeIDTest(helpers.PungiTestCase):
|
||||
def test_use_original_volume_id(self):
|
||||
compose = helpers.DummyCompose(self.topdir, {})
|
||||
|
||||
volid = extra_isos.get_volume_id(compose, compose.variants['Server'],
|
||||
'x86_64',
|
||||
'f-{volid}')
|
||||
|
||||
self.assertEqual(volid, 'f-test-1.0 Server.x86_64')
|
||||
|
||||
def test_falls_back_to_shorter(self):
|
||||
compose = helpers.DummyCompose(self.topdir, {})
|
||||
|
||||
volid = extra_isos.get_volume_id(compose, compose.variants['Server'],
|
||||
'x86_64',
|
||||
['long-foobar-{volid}', 'f-{volid}'])
|
||||
|
||||
self.assertEqual(volid, 'f-test-1.0 Server.x86_64')
|
||||
|
||||
def test_reports_unknown_placeholder(self):
|
||||
compose = helpers.DummyCompose(self.topdir, {})
|
||||
|
||||
with self.assertRaises(RuntimeError) as ctx:
|
||||
extra_isos.get_volume_id(compose, compose.variants['Server'],
|
||||
'x86_64', 'f-{boom}')
|
||||
|
||||
self.assertIn('boom', str(ctx.exception))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
Reference in New Issue
Block a user