lorax/docs/html/_modules/pylorax/api/recipes.html
Brian C. Lane 1ffd8562be New lorax documentation - 28.14.43
Related: rhbz#1826479
2020-04-27 16:33:01 -07:00

1478 lines
176 KiB
HTML

<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>pylorax.api.recipes &mdash; Lorax 28.14.42 documentation</title>
<script type="text/javascript" src="../../../_static/js/modernizr.min.js"></script>
<script type="text/javascript" id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script type="text/javascript" src="../../../_static/jquery.js"></script>
<script type="text/javascript" src="../../../_static/underscore.js"></script>
<script type="text/javascript" src="../../../_static/doctools.js"></script>
<script type="text/javascript" src="../../../_static/language_data.js"></script>
<script type="text/javascript" src="../../../_static/js/theme.js"></script>
<link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../../index.html" class="icon icon-home"> Lorax
</a>
<div class="version">
28.14.42
</div>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../../intro.html">Introduction to Lorax</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../intro.html#before-lorax">Before Lorax</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../lorax.html">Lorax</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../livemedia-creator.html">livemedia-creator</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../lorax-composer.html">lorax-composer</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../composer-cli.html">composer-cli</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../product-images.html">Product and Updates Images</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../modules.html">pylorax</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
<nav class="wy-nav-top" aria-label="top navigation">
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../../index.html">Lorax</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../../index.html">Docs</a> &raquo;</li>
<li><a href="../../index.html">Module code</a> &raquo;</li>
<li><a href="../../pylorax.html">pylorax</a> &raquo;</li>
<li>pylorax.api.recipes</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for pylorax.api.recipes</h1><div class="highlight"><pre>
<span></span><span class="c1">#</span>
<span class="c1"># Copyright (C) 2017-2019 Red Hat, Inc.</span>
<span class="c1">#</span>
<span class="c1"># This program is free software; you can redistribute it and/or modify</span>
<span class="c1"># it under the terms of the GNU General Public License as published by</span>
<span class="c1"># the Free Software Foundation; either version 2 of the License, or</span>
<span class="c1"># (at your option) any later version.</span>
<span class="c1">#</span>
<span class="c1"># This program is distributed in the hope that it will be useful,</span>
<span class="c1"># but WITHOUT ANY WARRANTY; without even the implied warranty of</span>
<span class="c1"># MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span>
<span class="c1"># GNU General Public License for more details.</span>
<span class="c1">#</span>
<span class="c1"># You should have received a copy of the GNU General Public License</span>
<span class="c1"># along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.</span>
<span class="c1">#</span>
<span class="kn">import</span> <span class="nn">gi</span>
<span class="n">gi</span><span class="o">.</span><span class="n">require_version</span><span class="p">(</span><span class="s2">&quot;Ggit&quot;</span><span class="p">,</span> <span class="s2">&quot;1.0&quot;</span><span class="p">)</span>
<span class="kn">from</span> <span class="nn">gi.repository</span> <span class="k">import</span> <span class="n">Ggit</span> <span class="k">as</span> <span class="n">Git</span>
<span class="kn">from</span> <span class="nn">gi.repository</span> <span class="k">import</span> <span class="n">Gio</span>
<span class="kn">from</span> <span class="nn">gi.repository</span> <span class="k">import</span> <span class="n">GLib</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">pytoml</span> <span class="k">as</span> <span class="nn">toml</span>
<span class="kn">import</span> <span class="nn">semantic_version</span> <span class="k">as</span> <span class="nn">semver</span>
<span class="kn">from</span> <span class="nn">pylorax.api.projects</span> <span class="k">import</span> <span class="n">dep_evra</span>
<span class="kn">from</span> <span class="nn">pylorax.base</span> <span class="k">import</span> <span class="n">DataHolder</span>
<span class="kn">from</span> <span class="nn">pylorax.sysutils</span> <span class="k">import</span> <span class="n">joinpaths</span>
<div class="viewcode-block" id="CommitTimeValError"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.CommitTimeValError">[docs]</a><span class="k">class</span> <span class="nc">CommitTimeValError</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="k">pass</span></div>
<div class="viewcode-block" id="RecipeFileError"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.RecipeFileError">[docs]</a><span class="k">class</span> <span class="nc">RecipeFileError</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="k">pass</span></div>
<div class="viewcode-block" id="RecipeError"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.RecipeError">[docs]</a><span class="k">class</span> <span class="nc">RecipeError</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="k">pass</span></div>
<div class="viewcode-block" id="Recipe"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.Recipe">[docs]</a><span class="k">class</span> <span class="nc">Recipe</span><span class="p">(</span><span class="nb">dict</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;A Recipe of package and modules</span>
<span class="sd"> This is a subclass of dict that enforces the constructor arguments</span>
<span class="sd"> and adds a .filename property to return the recipe&#39;s filename,</span>
<span class="sd"> and a .toml() function to return the recipe as a TOML string.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">description</span><span class="p">,</span> <span class="n">version</span><span class="p">,</span> <span class="n">modules</span><span class="p">,</span> <span class="n">packages</span><span class="p">,</span> <span class="n">groups</span><span class="p">,</span> <span class="n">customizations</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">gitrepos</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="c1"># Check that version is empty or semver compatible</span>
<span class="k">if</span> <span class="n">version</span><span class="p">:</span>
<span class="n">semver</span><span class="o">.</span><span class="n">Version</span><span class="p">(</span><span class="n">version</span><span class="p">)</span>
<span class="c1"># Make sure modules, packages, and groups are listed by their case-insensitive names</span>
<span class="k">if</span> <span class="n">modules</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">modules</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">modules</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">m</span><span class="p">:</span> <span class="n">m</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span>
<span class="k">if</span> <span class="n">packages</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">packages</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">packages</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">p</span><span class="p">:</span> <span class="n">p</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span>
<span class="k">if</span> <span class="n">groups</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">groups</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">groups</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">g</span><span class="p">:</span> <span class="n">g</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span>
<span class="c1"># Only support [[repos.git]] for now</span>
<span class="k">if</span> <span class="n">gitrepos</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">repos</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;git&quot;</span><span class="p">:</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">gitrepos</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">g</span><span class="p">:</span> <span class="n">g</span><span class="p">[</span><span class="s2">&quot;repo&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">())}</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">repos</span> <span class="o">=</span> <span class="kc">None</span>
<span class="nb">dict</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">name</span><span class="p">,</span>
<span class="n">description</span><span class="o">=</span><span class="n">description</span><span class="p">,</span>
<span class="n">version</span><span class="o">=</span><span class="n">version</span><span class="p">,</span>
<span class="n">modules</span><span class="o">=</span><span class="n">modules</span><span class="p">,</span>
<span class="n">packages</span><span class="o">=</span><span class="n">packages</span><span class="p">,</span>
<span class="n">groups</span><span class="o">=</span><span class="n">groups</span><span class="p">,</span>
<span class="n">customizations</span><span class="o">=</span><span class="n">customizations</span><span class="p">,</span>
<span class="n">repos</span><span class="o">=</span><span class="n">repos</span><span class="p">)</span>
<span class="c1"># We don&#39;t want customizations=None to show up in the TOML so remove it</span>
<span class="k">if</span> <span class="n">customizations</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">del</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;customizations&quot;</span><span class="p">]</span>
<span class="c1"># Don&#39;t include empty repos or repos.git</span>
<span class="k">if</span> <span class="n">repos</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">repos</span><span class="p">[</span><span class="s2">&quot;git&quot;</span><span class="p">]:</span>
<span class="k">del</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;repos&quot;</span><span class="p">]</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">package_names</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return the names of the packages&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="p">[</span><span class="n">p</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;packages&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="p">[]]</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">package_nver</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return the names and version globs of the packages&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="p">[(</span><span class="n">p</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">],</span> <span class="n">p</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">])</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;packages&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="p">[]]</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">module_names</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return the names of the modules&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="p">[</span><span class="n">m</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;modules&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="p">[]]</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">module_nver</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return the names and version globs of the modules&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="p">[(</span><span class="n">m</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">],</span> <span class="n">m</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">])</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;modules&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="p">[]]</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">group_names</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return the names of the groups. Groups do not have versions.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="nb">map</span><span class="p">(</span><span class="k">lambda</span> <span class="n">g</span><span class="p">:</span> <span class="n">g</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">],</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;groups&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="p">[])</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">filename</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return the Recipe&#39;s filename</span>
<span class="sd"> Replaces spaces in the name with &#39;-&#39; and appends .toml</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">recipe_filename</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">))</span>
<div class="viewcode-block" id="Recipe.toml"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.Recipe.toml">[docs]</a> <span class="k">def</span> <span class="nf">toml</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return the Recipe in TOML format&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">toml</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span></div>
<div class="viewcode-block" id="Recipe.bump_version"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.Recipe.bump_version">[docs]</a> <span class="k">def</span> <span class="nf">bump_version</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">old_version</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;semver recipe version number bump</span>
<span class="sd"> :param old_version: An optional old version number</span>
<span class="sd"> :type old_version: str</span>
<span class="sd"> :returns: The new version number or None</span>
<span class="sd"> :rtype: str</span>
<span class="sd"> :raises: ValueError</span>
<span class="sd"> If neither have a version, 0.0.1 is returned</span>
<span class="sd"> If there is no old version the new version is checked and returned</span>
<span class="sd"> If there is no new version, but there is a old one, bump its patch level</span>
<span class="sd"> If the old and new versions are the same, bump the patch level</span>
<span class="sd"> If they are different, check and return the new version</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">new_version</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;version&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">new_version</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">old_version</span><span class="p">:</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;0.0.1&quot;</span>
<span class="k">elif</span> <span class="n">new_version</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">old_version</span><span class="p">:</span>
<span class="n">semver</span><span class="o">.</span><span class="n">Version</span><span class="p">(</span><span class="n">new_version</span><span class="p">)</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_version</span>
<span class="k">elif</span> <span class="ow">not</span> <span class="n">new_version</span> <span class="ow">or</span> <span class="n">new_version</span> <span class="o">==</span> <span class="n">old_version</span><span class="p">:</span>
<span class="n">new_version</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">semver</span><span class="o">.</span><span class="n">Version</span><span class="p">(</span><span class="n">old_version</span><span class="p">)</span><span class="o">.</span><span class="n">next_patch</span><span class="p">())</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_version</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">semver</span><span class="o">.</span><span class="n">Version</span><span class="p">(</span><span class="n">new_version</span><span class="p">)</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_version</span>
<span class="c1"># Return the new version</span>
<span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">semver</span><span class="o">.</span><span class="n">Version</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">]))</span></div>
<div class="viewcode-block" id="Recipe.freeze"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.Recipe.freeze">[docs]</a> <span class="k">def</span> <span class="nf">freeze</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">deps</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot; Return a new Recipe with full module and package NEVRA</span>
<span class="sd"> :param deps: A list of dependency NEVRA to use to fill in the modules and packages</span>
<span class="sd"> :type deps: list(</span>
<span class="sd"> :returns: A new Recipe object</span>
<span class="sd"> :rtype: Recipe</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">module_names</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">module_names</span>
<span class="n">package_names</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">package_names</span>
<span class="n">group_names</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">group_names</span>
<span class="n">new_modules</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">new_packages</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">new_groups</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">dep</span> <span class="ow">in</span> <span class="n">deps</span><span class="p">:</span>
<span class="k">if</span> <span class="n">dep</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span> <span class="ow">in</span> <span class="n">package_names</span><span class="p">:</span>
<span class="n">new_packages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">RecipePackage</span><span class="p">(</span><span class="n">dep</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">],</span> <span class="n">dep_evra</span><span class="p">(</span><span class="n">dep</span><span class="p">)))</span>
<span class="k">elif</span> <span class="n">dep</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span> <span class="ow">in</span> <span class="n">module_names</span><span class="p">:</span>
<span class="n">new_modules</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">RecipeModule</span><span class="p">(</span><span class="n">dep</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">],</span> <span class="n">dep_evra</span><span class="p">(</span><span class="n">dep</span><span class="p">)))</span>
<span class="k">elif</span> <span class="n">dep</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span> <span class="ow">in</span> <span class="n">group_names</span><span class="p">:</span>
<span class="n">new_groups</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">RecipeGroup</span><span class="p">(</span><span class="n">dep</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]))</span>
<span class="k">if</span> <span class="s2">&quot;customizations&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
<span class="n">customizations</span> <span class="o">=</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;customizations&quot;</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">customizations</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="s2">&quot;repos&quot;</span> <span class="ow">in</span> <span class="bp">self</span> <span class="ow">and</span> <span class="s2">&quot;git&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;repos&quot;</span><span class="p">]:</span>
<span class="n">gitrepos</span> <span class="o">=</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;repos&quot;</span><span class="p">][</span><span class="s2">&quot;git&quot;</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">gitrepos</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">return</span> <span class="n">Recipe</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">],</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;description&quot;</span><span class="p">],</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">],</span>
<span class="n">new_modules</span><span class="p">,</span> <span class="n">new_packages</span><span class="p">,</span> <span class="n">new_groups</span><span class="p">,</span> <span class="n">customizations</span><span class="p">,</span> <span class="n">gitrepos</span><span class="p">)</span></div></div>
<div class="viewcode-block" id="RecipeModule"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.RecipeModule">[docs]</a><span class="k">class</span> <span class="nc">RecipeModule</span><span class="p">(</span><span class="nb">dict</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">version</span><span class="p">):</span>
<span class="nb">dict</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">name</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="n">version</span><span class="p">)</span></div>
<div class="viewcode-block" id="RecipePackage"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.RecipePackage">[docs]</a><span class="k">class</span> <span class="nc">RecipePackage</span><span class="p">(</span><span class="n">RecipeModule</span><span class="p">):</span>
<span class="k">pass</span></div>
<div class="viewcode-block" id="RecipeGroup"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.RecipeGroup">[docs]</a><span class="k">class</span> <span class="nc">RecipeGroup</span><span class="p">(</span><span class="nb">dict</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="nb">dict</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">name</span><span class="p">)</span></div>
<div class="viewcode-block" id="NewRecipeGit"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.NewRecipeGit">[docs]</a><span class="k">def</span> <span class="nf">NewRecipeGit</span><span class="p">(</span><span class="n">toml_dict</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Create a RecipeGit object from fields in a TOML dict</span>
<span class="sd"> :param rpmname: Name of the rpm to create, also used as the prefix name in the tar archive</span>
<span class="sd"> :type rpmname: str</span>
<span class="sd"> :param rpmversion: Version of the rpm, eg. &quot;1.0.0&quot;</span>
<span class="sd"> :type rpmversion: str</span>
<span class="sd"> :param rpmrelease: Release of the rpm, eg. &quot;1&quot;</span>
<span class="sd"> :type rpmrelease: str</span>
<span class="sd"> :param summary: Summary string for the rpm</span>
<span class="sd"> :type summary: str</span>
<span class="sd"> :param repo: URL of the get repo to clone and create the archive from</span>
<span class="sd"> :type repo: str</span>
<span class="sd"> :param ref: Git reference to check out. eg. origin/branch-name, git tag, or git commit hash</span>
<span class="sd"> :type ref: str</span>
<span class="sd"> :param destination: Path to install the / of the git repo at when installing the rpm</span>
<span class="sd"> :type destination: str</span>
<span class="sd"> :returns: A populated RecipeGit object</span>
<span class="sd"> :rtype: RecipeGit</span>
<span class="sd"> The TOML should look like this::</span>
<span class="sd"> [[repos.git]]</span>
<span class="sd"> rpmname=&quot;server-config&quot;</span>
<span class="sd"> rpmversion=&quot;1.0&quot;</span>
<span class="sd"> rpmrelease=&quot;1&quot;</span>
<span class="sd"> summary=&quot;Setup files for server deployment&quot;</span>
<span class="sd"> repo=&quot;PATH OF GIT REPO TO CLONE&quot;</span>
<span class="sd"> ref=&quot;v1.0&quot;</span>
<span class="sd"> destination=&quot;/opt/server/&quot;</span>
<span class="sd"> Note that the repo path supports anything that git supports, file://, https://, http://</span>
<span class="sd"> Currently there is no support for authentication</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">RecipeGit</span><span class="p">(</span><span class="n">toml_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;rpmname&quot;</span><span class="p">),</span>
<span class="n">toml_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;rpmversion&quot;</span><span class="p">),</span>
<span class="n">toml_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;rpmrelease&quot;</span><span class="p">),</span>
<span class="n">toml_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;summary&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">),</span>
<span class="n">toml_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;repo&quot;</span><span class="p">),</span>
<span class="n">toml_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;ref&quot;</span><span class="p">),</span>
<span class="n">toml_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;destination&quot;</span><span class="p">))</span></div>
<div class="viewcode-block" id="RecipeGit"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.RecipeGit">[docs]</a><span class="k">class</span> <span class="nc">RecipeGit</span><span class="p">(</span><span class="nb">dict</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">rpmname</span><span class="p">,</span> <span class="n">rpmversion</span><span class="p">,</span> <span class="n">rpmrelease</span><span class="p">,</span> <span class="n">summary</span><span class="p">,</span> <span class="n">repo</span><span class="p">,</span> <span class="n">ref</span><span class="p">,</span> <span class="n">destination</span><span class="p">):</span>
<span class="nb">dict</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">rpmname</span><span class="o">=</span><span class="n">rpmname</span><span class="p">,</span> <span class="n">rpmversion</span><span class="o">=</span><span class="n">rpmversion</span><span class="p">,</span> <span class="n">rpmrelease</span><span class="o">=</span><span class="n">rpmrelease</span><span class="p">,</span>
<span class="n">summary</span><span class="o">=</span><span class="n">summary</span><span class="p">,</span> <span class="n">repo</span><span class="o">=</span><span class="n">repo</span><span class="p">,</span> <span class="n">ref</span><span class="o">=</span><span class="n">ref</span><span class="p">,</span> <span class="n">destination</span><span class="o">=</span><span class="n">destination</span><span class="p">)</span></div>
<div class="viewcode-block" id="recipe_from_file"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.recipe_from_file">[docs]</a><span class="k">def</span> <span class="nf">recipe_from_file</span><span class="p">(</span><span class="n">recipe_path</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return a recipe file as a Recipe object</span>
<span class="sd"> :param recipe_path: Path to the recipe fila</span>
<span class="sd"> :type recipe_path: str</span>
<span class="sd"> :returns: A Recipe object</span>
<span class="sd"> :rtype: Recipe</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">recipe_path</span><span class="p">,</span> <span class="s1">&#39;rb&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="k">return</span> <span class="n">recipe_from_toml</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">())</span></div>
<div class="viewcode-block" id="recipe_from_toml"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.recipe_from_toml">[docs]</a><span class="k">def</span> <span class="nf">recipe_from_toml</span><span class="p">(</span><span class="n">recipe_str</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Create a Recipe object from a toml string.</span>
<span class="sd"> :param recipe_str: The Recipe TOML string</span>
<span class="sd"> :type recipe_str: str</span>
<span class="sd"> :returns: A Recipe object</span>
<span class="sd"> :rtype: Recipe</span>
<span class="sd"> :raises: TomlError</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">recipe_dict</span> <span class="o">=</span> <span class="n">toml</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">recipe_str</span><span class="p">)</span>
<span class="k">return</span> <span class="n">recipe_from_dict</span><span class="p">(</span><span class="n">recipe_dict</span><span class="p">)</span></div>
<div class="viewcode-block" id="check_required_list"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.check_required_list">[docs]</a><span class="k">def</span> <span class="nf">check_required_list</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="n">fields</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Check a list of dicts for required fields</span>
<span class="sd"> :param lst: A list of dicts with fields</span>
<span class="sd"> :type lst: list of dict</span>
<span class="sd"> :param fields: A list of field name strings</span>
<span class="sd"> :type fields: list of str</span>
<span class="sd"> :returns: A list of error strings</span>
<span class="sd"> :rtype: list of str</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">errors</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">lst</span><span class="p">):</span>
<span class="n">m_errs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">errors</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">check_list_case</span><span class="p">(</span><span class="n">fields</span><span class="p">,</span> <span class="n">m</span><span class="o">.</span><span class="n">keys</span><span class="p">(),</span> <span class="n">prefix</span><span class="o">=</span><span class="s2">&quot;</span><span class="si">%d</span><span class="s2"> &quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">)))</span>
<span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">fields</span><span class="p">:</span>
<span class="k">if</span> <span class="n">f</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">m</span><span class="p">:</span>
<span class="n">m_errs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&#39;</span><span class="si">%s</span><span class="s2">&#39;&quot;</span> <span class="o">%</span> <span class="n">f</span><span class="p">)</span>
<span class="k">if</span> <span class="n">m_errs</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">%d</span><span class="s2"> is missing </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="s2">&quot;, &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">m_errs</span><span class="p">)))</span>
<span class="k">return</span> <span class="n">errors</span></div>
<div class="viewcode-block" id="check_list_case"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.check_list_case">[docs]</a><span class="k">def</span> <span class="nf">check_list_case</span><span class="p">(</span><span class="n">expected_keys</span><span class="p">,</span> <span class="n">recipe_keys</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Check the case of the recipe keys</span>
<span class="sd"> :param expected_keys: A list of expected key strings</span>
<span class="sd"> :type expected_keys: list of str</span>
<span class="sd"> :param recipe_keys: A list of the recipe&#39;s key strings</span>
<span class="sd"> :type recipe_keys: list of str</span>
<span class="sd"> :returns: list of errors</span>
<span class="sd"> :rtype: list of str</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">errors</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">recipe_keys</span><span class="p">:</span>
<span class="k">if</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">expected_keys</span><span class="p">:</span>
<span class="k">continue</span>
<span class="k">if</span> <span class="n">k</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">in</span> <span class="n">expected_keys</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">prefix</span> <span class="o">+</span> <span class="s2">&quot;</span><span class="si">%s</span><span class="s2"> should be </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">k</span><span class="o">.</span><span class="n">lower</span><span class="p">()))</span>
<span class="k">return</span> <span class="n">errors</span></div>
<div class="viewcode-block" id="check_recipe_dict"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.check_recipe_dict">[docs]</a><span class="k">def</span> <span class="nf">check_recipe_dict</span><span class="p">(</span><span class="n">recipe_dict</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Check a dict before using it to create a new Recipe</span>
<span class="sd"> :param recipe_dict: A plain dict of the recipe</span>
<span class="sd"> :type recipe_dict: dict</span>
<span class="sd"> :returns: True if dict is ok</span>
<span class="sd"> :rtype: bool</span>
<span class="sd"> :raises: RecipeError</span>
<span class="sd"> This checks a dict to make sure required fields are present,</span>
<span class="sd"> that optional fields are correct, and that other optional fields</span>
<span class="sd"> are of the correct format, when included.</span>
<span class="sd"> This collects all of the errors and returns a single RecipeError with</span>
<span class="sd"> a string that can be presented to users.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">errors</span> <span class="o">=</span> <span class="p">[]</span>
<span class="c1"># Check for wrong case of top level keys</span>
<span class="n">top_keys</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">,</span> <span class="s2">&quot;description&quot;</span><span class="p">,</span> <span class="s2">&quot;version&quot;</span><span class="p">,</span> <span class="s2">&quot;modules&quot;</span><span class="p">,</span> <span class="s2">&quot;packages&quot;</span><span class="p">,</span> <span class="s2">&quot;groups&quot;</span><span class="p">,</span> <span class="s2">&quot;repos&quot;</span><span class="p">,</span> <span class="s2">&quot;customizations&quot;</span><span class="p">]</span>
<span class="n">errors</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">check_list_case</span><span class="p">(</span><span class="n">recipe_dict</span><span class="o">.</span><span class="n">keys</span><span class="p">(),</span> <span class="n">top_keys</span><span class="p">))</span>
<span class="k">if</span> <span class="s2">&quot;name&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">recipe_dict</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;Missing &#39;name&#39;&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="s2">&quot;description&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">recipe_dict</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;Missing &#39;description&#39;&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="s2">&quot;version&quot;</span> <span class="ow">in</span> <span class="n">recipe_dict</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">semver</span><span class="o">.</span><span class="n">Version</span><span class="p">(</span><span class="n">recipe_dict</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">])</span>
<span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;Invalid &#39;version&#39;, must use Semantic Versioning&quot;</span><span class="p">)</span>
<span class="c1"># Examine all the modules</span>
<span class="k">if</span> <span class="n">recipe_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;modules&quot;</span><span class="p">):</span>
<span class="n">module_errors</span> <span class="o">=</span> <span class="n">check_required_list</span><span class="p">(</span><span class="n">recipe_dict</span><span class="p">[</span><span class="s2">&quot;modules&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">,</span> <span class="s2">&quot;version&quot;</span><span class="p">])</span>
<span class="k">if</span> <span class="n">module_errors</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&#39;modules&#39; errors:</span><span class="se">\n</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">module_errors</span><span class="p">))</span>
<span class="c1"># Examine all the packages</span>
<span class="k">if</span> <span class="n">recipe_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;packages&quot;</span><span class="p">):</span>
<span class="n">package_errors</span> <span class="o">=</span> <span class="n">check_required_list</span><span class="p">(</span><span class="n">recipe_dict</span><span class="p">[</span><span class="s2">&quot;packages&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">,</span> <span class="s2">&quot;version&quot;</span><span class="p">])</span>
<span class="k">if</span> <span class="n">package_errors</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&#39;packages&#39; errors:</span><span class="se">\n</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">package_errors</span><span class="p">))</span>
<span class="k">if</span> <span class="n">recipe_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;groups&quot;</span><span class="p">):</span>
<span class="n">groups_errors</span> <span class="o">=</span> <span class="n">check_required_list</span><span class="p">(</span><span class="n">recipe_dict</span><span class="p">[</span><span class="s2">&quot;groups&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">])</span>
<span class="k">if</span> <span class="n">groups_errors</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&#39;groups&#39; errors:</span><span class="se">\n</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">groups_errors</span><span class="p">))</span>
<span class="k">if</span> <span class="n">recipe_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;repos&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">recipe_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;repos&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;git&quot;</span><span class="p">):</span>
<span class="n">repos_errors</span> <span class="o">=</span> <span class="n">check_required_list</span><span class="p">(</span><span class="n">recipe_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;repos&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;git&quot;</span><span class="p">),</span>
<span class="p">[</span><span class="s2">&quot;rpmname&quot;</span><span class="p">,</span> <span class="s2">&quot;rpmversion&quot;</span><span class="p">,</span> <span class="s2">&quot;rpmrelease&quot;</span><span class="p">,</span> <span class="s2">&quot;summary&quot;</span><span class="p">,</span> <span class="s2">&quot;repo&quot;</span><span class="p">,</span> <span class="s2">&quot;ref&quot;</span><span class="p">,</span> <span class="s2">&quot;destination&quot;</span><span class="p">])</span>
<span class="k">if</span> <span class="n">repos_errors</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&#39;repos.git&#39; errors:</span><span class="se">\n</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">repos_errors</span><span class="p">))</span>
<span class="c1"># No customizations to check, exit now</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">recipe_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;customizations&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">c</span><span class="p">:</span>
<span class="k">return</span> <span class="n">errors</span>
<span class="c1"># Make sure to catch empty sections by testing for keywords, not just looking at .get() result.</span>
<span class="k">if</span> <span class="s2">&quot;kernel&quot;</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">check_list_case</span><span class="p">([</span><span class="s2">&quot;append&quot;</span><span class="p">],</span> <span class="n">c</span><span class="p">[</span><span class="s2">&quot;kernel&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">keys</span><span class="p">(),</span> <span class="n">prefix</span><span class="o">=</span><span class="s2">&quot;kernel &quot;</span><span class="p">))</span>
<span class="k">if</span> <span class="s2">&quot;append&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;kernel&quot;</span><span class="p">,</span> <span class="p">[]):</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&#39;customizations.kernel&#39;: missing append field.&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="s2">&quot;sshkey&quot;</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
<span class="n">sshkey_errors</span> <span class="o">=</span> <span class="n">check_required_list</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;sshkey&quot;</span><span class="p">),</span> <span class="p">[</span><span class="s2">&quot;user&quot;</span><span class="p">,</span> <span class="s2">&quot;key&quot;</span><span class="p">])</span>
<span class="k">if</span> <span class="n">sshkey_errors</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&#39;customizations.sshkey&#39; errors:</span><span class="se">\n</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">sshkey_errors</span><span class="p">))</span>
<span class="k">if</span> <span class="s2">&quot;user&quot;</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
<span class="n">user_errors</span> <span class="o">=</span> <span class="n">check_required_list</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;user&quot;</span><span class="p">),</span> <span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">])</span>
<span class="k">if</span> <span class="n">user_errors</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&#39;customizations.user&#39; errors:</span><span class="se">\n</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">user_errors</span><span class="p">))</span>
<span class="k">if</span> <span class="s2">&quot;group&quot;</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
<span class="n">group_errors</span> <span class="o">=</span> <span class="n">check_required_list</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;group&quot;</span><span class="p">),</span> <span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">])</span>
<span class="k">if</span> <span class="n">group_errors</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&#39;customizations.group&#39; errors:</span><span class="se">\n</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">group_errors</span><span class="p">))</span>
<span class="k">if</span> <span class="s2">&quot;timezone&quot;</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">check_list_case</span><span class="p">([</span><span class="s2">&quot;timezone&quot;</span><span class="p">,</span> <span class="s2">&quot;ntpservers&quot;</span><span class="p">],</span> <span class="n">c</span><span class="p">[</span><span class="s2">&quot;timezone&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">keys</span><span class="p">(),</span> <span class="n">prefix</span><span class="o">=</span><span class="s2">&quot;timezone &quot;</span><span class="p">))</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;timezone&quot;</span><span class="p">):</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&#39;customizations.timezone&#39;: missing timezone or ntpservers fields.&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="s2">&quot;locale&quot;</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">check_list_case</span><span class="p">([</span><span class="s2">&quot;languages&quot;</span><span class="p">,</span> <span class="s2">&quot;keyboard&quot;</span><span class="p">],</span> <span class="n">c</span><span class="p">[</span><span class="s2">&quot;locale&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">keys</span><span class="p">(),</span> <span class="n">prefix</span><span class="o">=</span><span class="s2">&quot;locale &quot;</span><span class="p">))</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;locale&quot;</span><span class="p">):</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&#39;customizations.locale&#39;: missing languages or keyboard fields.&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="s2">&quot;firewall&quot;</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">check_list_case</span><span class="p">([</span><span class="s2">&quot;ports&quot;</span><span class="p">],</span> <span class="n">c</span><span class="p">[</span><span class="s2">&quot;firewall&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">keys</span><span class="p">(),</span> <span class="n">prefix</span><span class="o">=</span><span class="s2">&quot;firewall &quot;</span><span class="p">))</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;firewall&quot;</span><span class="p">):</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&#39;customizations.firewall&#39;: missing ports field or services section.&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="s2">&quot;services&quot;</span> <span class="ow">in</span> <span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;firewall&quot;</span><span class="p">,</span> <span class="p">[]):</span>
<span class="n">errors</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">check_list_case</span><span class="p">([</span><span class="s2">&quot;enabled&quot;</span><span class="p">,</span> <span class="s2">&quot;disabled&quot;</span><span class="p">],</span> <span class="n">c</span><span class="p">[</span><span class="s2">&quot;firewall&quot;</span><span class="p">][</span><span class="s2">&quot;services&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">keys</span><span class="p">(),</span> <span class="n">prefix</span><span class="o">=</span><span class="s2">&quot;firewall.services &quot;</span><span class="p">))</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;firewall&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;services&quot;</span><span class="p">):</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&#39;customizations.firewall.services&#39;: missing enabled or disabled fields.&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="s2">&quot;services&quot;</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
<span class="n">errors</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">check_list_case</span><span class="p">([</span><span class="s2">&quot;enabled&quot;</span><span class="p">,</span> <span class="s2">&quot;disabled&quot;</span><span class="p">],</span> <span class="n">c</span><span class="p">[</span><span class="s2">&quot;services&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">keys</span><span class="p">(),</span> <span class="n">prefix</span><span class="o">=</span><span class="s2">&quot;services &quot;</span><span class="p">))</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;services&quot;</span><span class="p">):</span>
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&#39;customizations.services&#39;: missing enabled or disabled fields.&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">errors</span></div>
<div class="viewcode-block" id="recipe_from_dict"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.recipe_from_dict">[docs]</a><span class="k">def</span> <span class="nf">recipe_from_dict</span><span class="p">(</span><span class="n">recipe_dict</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Create a Recipe object from a plain dict.</span>
<span class="sd"> :param recipe_dict: A plain dict of the recipe</span>
<span class="sd"> :type recipe_dict: dict</span>
<span class="sd"> :returns: A Recipe object</span>
<span class="sd"> :rtype: Recipe</span>
<span class="sd"> :raises: RecipeError</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">errors</span> <span class="o">=</span> <span class="n">check_recipe_dict</span><span class="p">(</span><span class="n">recipe_dict</span><span class="p">)</span>
<span class="k">if</span> <span class="n">errors</span><span class="p">:</span>
<span class="n">msg</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">errors</span><span class="p">)</span>
<span class="k">raise</span> <span class="n">RecipeError</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
<span class="c1"># Make RecipeModule objects from the toml</span>
<span class="c1"># The TOML may not have modules or packages in it. Set them to None in this case</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">if</span> <span class="n">recipe_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;modules&quot;</span><span class="p">):</span>
<span class="n">modules</span> <span class="o">=</span> <span class="p">[</span><span class="n">RecipeModule</span><span class="p">(</span><span class="n">m</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">),</span> <span class="n">m</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;version&quot;</span><span class="p">))</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">recipe_dict</span><span class="p">[</span><span class="s2">&quot;modules&quot;</span><span class="p">]]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">modules</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">if</span> <span class="n">recipe_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;packages&quot;</span><span class="p">):</span>
<span class="n">packages</span> <span class="o">=</span> <span class="p">[</span><span class="n">RecipePackage</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">),</span> <span class="n">p</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;version&quot;</span><span class="p">))</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">recipe_dict</span><span class="p">[</span><span class="s2">&quot;packages&quot;</span><span class="p">]]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">packages</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">if</span> <span class="n">recipe_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;groups&quot;</span><span class="p">):</span>
<span class="n">groups</span> <span class="o">=</span> <span class="p">[</span><span class="n">RecipeGroup</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">))</span> <span class="k">for</span> <span class="n">g</span> <span class="ow">in</span> <span class="n">recipe_dict</span><span class="p">[</span><span class="s2">&quot;groups&quot;</span><span class="p">]]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">groups</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">if</span> <span class="n">recipe_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;repos&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">recipe_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;repos&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;git&quot;</span><span class="p">):</span>
<span class="n">gitrepos</span> <span class="o">=</span> <span class="p">[</span><span class="n">NewRecipeGit</span><span class="p">(</span><span class="n">r</span><span class="p">)</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">recipe_dict</span><span class="p">[</span><span class="s2">&quot;repos&quot;</span><span class="p">][</span><span class="s2">&quot;git&quot;</span><span class="p">]]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">gitrepos</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">recipe_dict</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span>
<span class="n">description</span> <span class="o">=</span> <span class="n">recipe_dict</span><span class="p">[</span><span class="s2">&quot;description&quot;</span><span class="p">]</span>
<span class="n">version</span> <span class="o">=</span> <span class="n">recipe_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;version&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="n">customizations</span> <span class="o">=</span> <span class="n">recipe_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;customizations&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="c1"># [customizations] was incorrectly documented at first, so we have to support using it</span>
<span class="c1"># as [[customizations]] by grabbing the first element.</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">customizations</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
<span class="n">customizations</span> <span class="o">=</span> <span class="n">customizations</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">except</span> <span class="ne">KeyError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">RecipeError</span><span class="p">(</span><span class="s2">&quot;There was a problem parsing the recipe: </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
<span class="k">return</span> <span class="n">Recipe</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">description</span><span class="p">,</span> <span class="n">version</span><span class="p">,</span> <span class="n">modules</span><span class="p">,</span> <span class="n">packages</span><span class="p">,</span> <span class="n">groups</span><span class="p">,</span> <span class="n">customizations</span><span class="p">,</span> <span class="n">gitrepos</span><span class="p">)</span></div>
<div class="viewcode-block" id="gfile"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.gfile">[docs]</a><span class="k">def</span> <span class="nf">gfile</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Convert a string path to GFile for use with Git&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">Gio</span><span class="o">.</span><span class="n">file_new_for_path</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></div>
<div class="viewcode-block" id="recipe_filename"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.recipe_filename">[docs]</a><span class="k">def</span> <span class="nf">recipe_filename</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return the toml filename for a recipe</span>
<span class="sd"> Replaces spaces with &#39;-&#39; and appends &#39;.toml&#39;</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># XXX Raise and error if this is empty?</span>
<span class="k">return</span> <span class="n">name</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot; &quot;</span><span class="p">,</span> <span class="s2">&quot;-&quot;</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;.toml&quot;</span></div>
<div class="viewcode-block" id="head_commit"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.head_commit">[docs]</a><span class="k">def</span> <span class="nf">head_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Get the branch&#39;s HEAD Commit Object</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :returns: Branch&#39;s head commit</span>
<span class="sd"> :rtype: Git.Commit</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">branch_obj</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">lookup_branch</span><span class="p">(</span><span class="n">branch</span><span class="p">,</span> <span class="n">Git</span><span class="o">.</span><span class="n">BranchType</span><span class="o">.</span><span class="n">LOCAL</span><span class="p">)</span>
<span class="n">commit_id</span> <span class="o">=</span> <span class="n">branch_obj</span><span class="o">.</span><span class="n">get_target</span><span class="p">()</span>
<span class="k">return</span> <span class="n">repo</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">commit_id</span><span class="p">,</span> <span class="n">Git</span><span class="o">.</span><span class="n">Commit</span><span class="p">)</span></div>
<div class="viewcode-block" id="prepare_commit"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.prepare_commit">[docs]</a><span class="k">def</span> <span class="nf">prepare_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">builder</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Prepare for a commit</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param builder: instance of TreeBuilder</span>
<span class="sd"> :type builder: TreeBuilder</span>
<span class="sd"> :returns: (Tree, Sig, Ref)</span>
<span class="sd"> :rtype: tuple</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">tree_id</span> <span class="o">=</span> <span class="n">builder</span><span class="o">.</span><span class="n">write</span><span class="p">()</span>
<span class="n">tree</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">tree_id</span><span class="p">,</span> <span class="n">Git</span><span class="o">.</span><span class="n">Tree</span><span class="p">)</span>
<span class="n">sig</span> <span class="o">=</span> <span class="n">Git</span><span class="o">.</span><span class="n">Signature</span><span class="o">.</span><span class="n">new_now</span><span class="p">(</span><span class="s2">&quot;bdcs-api-server&quot;</span><span class="p">,</span> <span class="s2">&quot;user-email&quot;</span><span class="p">)</span>
<span class="n">ref</span> <span class="o">=</span> <span class="s2">&quot;refs/heads/</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">branch</span>
<span class="k">return</span> <span class="p">(</span><span class="n">tree</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="n">ref</span><span class="p">)</span></div>
<div class="viewcode-block" id="open_or_create_repo"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.open_or_create_repo">[docs]</a><span class="k">def</span> <span class="nf">open_or_create_repo</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Open an existing repo, or create a new one</span>
<span class="sd"> :param path: path to recipe directory</span>
<span class="sd"> :type path: string</span>
<span class="sd"> :returns: A repository object</span>
<span class="sd"> :rtype: Git.Repository</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> A bare git repo will be created in the git directory of the specified path.</span>
<span class="sd"> If a repo already exists it will be opened and returned instead of</span>
<span class="sd"> creating a new one.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">Git</span><span class="o">.</span><span class="n">init</span><span class="p">()</span>
<span class="n">git_path</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s2">&quot;git&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">git_path</span><span class="p">,</span> <span class="s2">&quot;HEAD&quot;</span><span class="p">)):</span>
<span class="k">return</span> <span class="n">Git</span><span class="o">.</span><span class="n">Repository</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">gfile</span><span class="p">(</span><span class="n">git_path</span><span class="p">))</span>
<span class="n">repo</span> <span class="o">=</span> <span class="n">Git</span><span class="o">.</span><span class="n">Repository</span><span class="o">.</span><span class="n">init_repository</span><span class="p">(</span><span class="n">gfile</span><span class="p">(</span><span class="n">git_path</span><span class="p">),</span> <span class="kc">True</span><span class="p">)</span>
<span class="c1"># Make an initial empty commit</span>
<span class="n">sig</span> <span class="o">=</span> <span class="n">Git</span><span class="o">.</span><span class="n">Signature</span><span class="o">.</span><span class="n">new_now</span><span class="p">(</span><span class="s2">&quot;bdcs-api-server&quot;</span><span class="p">,</span> <span class="s2">&quot;user-email&quot;</span><span class="p">)</span>
<span class="n">tree_id</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">get_index</span><span class="p">()</span><span class="o">.</span><span class="n">write_tree</span><span class="p">()</span>
<span class="n">tree</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">tree_id</span><span class="p">,</span> <span class="n">Git</span><span class="o">.</span><span class="n">Tree</span><span class="p">)</span>
<span class="n">repo</span><span class="o">.</span><span class="n">create_commit</span><span class="p">(</span><span class="s2">&quot;HEAD&quot;</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="s2">&quot;UTF-8&quot;</span><span class="p">,</span> <span class="s2">&quot;Initial Recipe repository commit&quot;</span><span class="p">,</span> <span class="n">tree</span><span class="p">,</span> <span class="p">[])</span>
<span class="k">return</span> <span class="n">repo</span></div>
<div class="viewcode-block" id="write_commit"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.write_commit">[docs]</a><span class="k">def</span> <span class="nf">write_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">content</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Make a new commit to a repository&#39;s branch</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param filename: full path of the file to add</span>
<span class="sd"> :type filename: str</span>
<span class="sd"> :param message: The commit message</span>
<span class="sd"> :type message: str</span>
<span class="sd"> :param content: The data to write</span>
<span class="sd"> :type content: str</span>
<span class="sd"> :returns: OId of the new commit</span>
<span class="sd"> :rtype: Git.OId</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">parent_commit</span> <span class="o">=</span> <span class="n">head_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">)</span>
<span class="k">except</span> <span class="n">GLib</span><span class="o">.</span><span class="n">GError</span><span class="p">:</span>
<span class="c1"># Branch doesn&#39;t exist, make a new one based on master</span>
<span class="n">master_head</span> <span class="o">=</span> <span class="n">head_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="s2">&quot;master&quot;</span><span class="p">)</span>
<span class="n">repo</span><span class="o">.</span><span class="n">create_branch</span><span class="p">(</span><span class="n">branch</span><span class="p">,</span> <span class="n">master_head</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">parent_commit</span> <span class="o">=</span> <span class="n">head_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">)</span>
<span class="n">parent_commit</span> <span class="o">=</span> <span class="n">head_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">)</span>
<span class="n">blob_id</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">create_blob_from_buffer</span><span class="p">(</span><span class="n">content</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;UTF-8&quot;</span><span class="p">))</span>
<span class="c1"># Use treebuilder to make a new entry for this filename and blob</span>
<span class="n">parent_tree</span> <span class="o">=</span> <span class="n">parent_commit</span><span class="o">.</span><span class="n">get_tree</span><span class="p">()</span>
<span class="n">builder</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">create_tree_builder_from_tree</span><span class="p">(</span><span class="n">parent_tree</span><span class="p">)</span>
<span class="n">builder</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">blob_id</span><span class="p">,</span> <span class="n">Git</span><span class="o">.</span><span class="n">FileMode</span><span class="o">.</span><span class="n">BLOB</span><span class="p">)</span>
<span class="p">(</span><span class="n">tree</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="n">ref</span><span class="p">)</span> <span class="o">=</span> <span class="n">prepare_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">builder</span><span class="p">)</span>
<span class="k">return</span> <span class="n">repo</span><span class="o">.</span><span class="n">create_commit</span><span class="p">(</span><span class="n">ref</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="s2">&quot;UTF-8&quot;</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">tree</span><span class="p">,</span> <span class="p">[</span><span class="n">parent_commit</span><span class="p">])</span></div>
<div class="viewcode-block" id="read_commit_spec"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.read_commit_spec">[docs]</a><span class="k">def</span> <span class="nf">read_commit_spec</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">spec</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return the raw content of the blob specified by the spec</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param spec: Git revparse spec</span>
<span class="sd"> :type spec: str</span>
<span class="sd"> :returns: Contents of the commit</span>
<span class="sd"> :rtype: str</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> eg. To read the README file from master the spec is &quot;master:README&quot;</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">commit_id</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">revparse</span><span class="p">(</span><span class="n">spec</span><span class="p">)</span><span class="o">.</span><span class="n">get_id</span><span class="p">()</span>
<span class="n">blob</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">commit_id</span><span class="p">,</span> <span class="n">Git</span><span class="o">.</span><span class="n">Blob</span><span class="p">)</span>
<span class="k">return</span> <span class="n">blob</span><span class="o">.</span><span class="n">get_raw_content</span><span class="p">()</span></div>
<div class="viewcode-block" id="read_commit"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.read_commit">[docs]</a><span class="k">def</span> <span class="nf">read_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="n">commit</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return the contents of a file on a specific branch or commit.</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param filename: filename to read</span>
<span class="sd"> :type filename: str</span>
<span class="sd"> :param commit: Optional commit hash</span>
<span class="sd"> :type commit: str</span>
<span class="sd"> :returns: The commit id, and the contents of the commit</span>
<span class="sd"> :rtype: tuple(str, str)</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> If no commit is passed the master:filename is returned, otherwise it will be</span>
<span class="sd"> commit:filename</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">commit</span><span class="p">:</span>
<span class="c1"># Find the most recent commit for filename on the selected branch</span>
<span class="n">commits</span> <span class="o">=</span> <span class="n">list_commits</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">commits</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">RecipeError</span><span class="p">(</span><span class="s2">&quot;No commits for </span><span class="si">%s</span><span class="s2"> on the </span><span class="si">%s</span><span class="s2"> branch.&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">branch</span><span class="p">))</span>
<span class="n">commit</span> <span class="o">=</span> <span class="n">commits</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">commit</span>
<span class="k">return</span> <span class="p">(</span><span class="n">commit</span><span class="p">,</span> <span class="n">read_commit_spec</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="s2">&quot;</span><span class="si">%s</span><span class="s2">:</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">commit</span><span class="p">,</span> <span class="n">filename</span><span class="p">)))</span></div>
<div class="viewcode-block" id="read_recipe_commit"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.read_recipe_commit">[docs]</a><span class="k">def</span> <span class="nf">read_recipe_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe_name</span><span class="p">,</span> <span class="n">commit</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Read a recipe commit from git and return a Recipe object</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param recipe_name: Recipe name to read</span>
<span class="sd"> :type recipe_name: str</span>
<span class="sd"> :param commit: Optional commit hash</span>
<span class="sd"> :type commit: str</span>
<span class="sd"> :returns: A Recipe object</span>
<span class="sd"> :rtype: Recipe</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> If no commit is passed the master:filename is returned, otherwise it will be</span>
<span class="sd"> commit:filename</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">repo_file_exists</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe_filename</span><span class="p">(</span><span class="n">recipe_name</span><span class="p">)):</span>
<span class="k">raise</span> <span class="n">RecipeFileError</span><span class="p">(</span><span class="s2">&quot;Unknown blueprint&quot;</span><span class="p">)</span>
<span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="n">recipe_toml</span><span class="p">)</span> <span class="o">=</span> <span class="n">read_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe_filename</span><span class="p">(</span><span class="n">recipe_name</span><span class="p">),</span> <span class="n">commit</span><span class="p">)</span>
<span class="k">return</span> <span class="n">recipe_from_toml</span><span class="p">(</span><span class="n">recipe_toml</span><span class="p">)</span></div>
<div class="viewcode-block" id="read_recipe_and_id"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.read_recipe_and_id">[docs]</a><span class="k">def</span> <span class="nf">read_recipe_and_id</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe_name</span><span class="p">,</span> <span class="n">commit</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Read a recipe commit and its id from git</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param recipe_name: Recipe name to read</span>
<span class="sd"> :type recipe_name: str</span>
<span class="sd"> :param commit: Optional commit hash</span>
<span class="sd"> :type commit: str</span>
<span class="sd"> :returns: The commit id, and a Recipe object</span>
<span class="sd"> :rtype: tuple(str, Recipe)</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> If no commit is passed the master:filename is returned, otherwise it will be</span>
<span class="sd"> commit:filename</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="p">(</span><span class="n">commit_id</span><span class="p">,</span> <span class="n">recipe_toml</span><span class="p">)</span> <span class="o">=</span> <span class="n">read_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe_filename</span><span class="p">(</span><span class="n">recipe_name</span><span class="p">),</span> <span class="n">commit</span><span class="p">)</span>
<span class="k">return</span> <span class="p">(</span><span class="n">commit_id</span><span class="p">,</span> <span class="n">recipe_from_toml</span><span class="p">(</span><span class="n">recipe_toml</span><span class="p">))</span></div>
<div class="viewcode-block" id="list_branch_files"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.list_branch_files">[docs]</a><span class="k">def</span> <span class="nf">list_branch_files</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return a sorted list of the files on the branch HEAD</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :returns: A sorted list of the filenames</span>
<span class="sd"> :rtype: list(str)</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">commit</span> <span class="o">=</span> <span class="n">head_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">)</span><span class="o">.</span><span class="n">get_id</span><span class="p">()</span><span class="o">.</span><span class="n">to_string</span><span class="p">()</span>
<span class="k">return</span> <span class="n">list_commit_files</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">commit</span><span class="p">)</span></div>
<div class="viewcode-block" id="list_commit_files"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.list_commit_files">[docs]</a><span class="k">def</span> <span class="nf">list_commit_files</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">commit</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return a sorted list of the files on a commit</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param commit: The commit hash to list</span>
<span class="sd"> :type commit: str</span>
<span class="sd"> :returns: A sorted list of the filenames</span>
<span class="sd"> :rtype: list(str)</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">commit_id</span> <span class="o">=</span> <span class="n">Git</span><span class="o">.</span><span class="n">OId</span><span class="o">.</span><span class="n">new_from_string</span><span class="p">(</span><span class="n">commit</span><span class="p">)</span>
<span class="n">commit_obj</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">commit_id</span><span class="p">,</span> <span class="n">Git</span><span class="o">.</span><span class="n">Commit</span><span class="p">)</span>
<span class="n">tree</span> <span class="o">=</span> <span class="n">commit_obj</span><span class="o">.</span><span class="n">get_tree</span><span class="p">()</span>
<span class="k">return</span> <span class="nb">sorted</span><span class="p">([</span><span class="n">tree</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="o">.</span><span class="n">get_name</span><span class="p">()</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">tree</span><span class="o">.</span><span class="n">size</span><span class="p">())])</span></div>
<div class="viewcode-block" id="delete_recipe"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.delete_recipe">[docs]</a><span class="k">def</span> <span class="nf">delete_recipe</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe_name</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Delete a recipe from a branch.</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param recipe_name: Recipe name to delete</span>
<span class="sd"> :type recipe_name: str</span>
<span class="sd"> :returns: OId of the new commit</span>
<span class="sd"> :rtype: Git.OId</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">delete_file</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe_filename</span><span class="p">(</span><span class="n">recipe_name</span><span class="p">))</span></div>
<div class="viewcode-block" id="delete_file"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.delete_file">[docs]</a><span class="k">def</span> <span class="nf">delete_file</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Delete a file from a branch.</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param filename: filename to delete</span>
<span class="sd"> :type filename: str</span>
<span class="sd"> :returns: OId of the new commit</span>
<span class="sd"> :rtype: Git.OId</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">parent_commit</span> <span class="o">=</span> <span class="n">head_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">)</span>
<span class="n">parent_tree</span> <span class="o">=</span> <span class="n">parent_commit</span><span class="o">.</span><span class="n">get_tree</span><span class="p">()</span>
<span class="n">builder</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">create_tree_builder_from_tree</span><span class="p">(</span><span class="n">parent_tree</span><span class="p">)</span>
<span class="n">builder</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
<span class="p">(</span><span class="n">tree</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="n">ref</span><span class="p">)</span> <span class="o">=</span> <span class="n">prepare_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">builder</span><span class="p">)</span>
<span class="n">message</span> <span class="o">=</span> <span class="s2">&quot;Recipe </span><span class="si">%s</span><span class="s2"> deleted&quot;</span> <span class="o">%</span> <span class="n">filename</span>
<span class="k">return</span> <span class="n">repo</span><span class="o">.</span><span class="n">create_commit</span><span class="p">(</span><span class="n">ref</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="s2">&quot;UTF-8&quot;</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">tree</span><span class="p">,</span> <span class="p">[</span><span class="n">parent_commit</span><span class="p">])</span></div>
<div class="viewcode-block" id="revert_recipe"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.revert_recipe">[docs]</a><span class="k">def</span> <span class="nf">revert_recipe</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe_name</span><span class="p">,</span> <span class="n">commit</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Revert the contents of a recipe to that of a previous commit</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param recipe_name: Recipe name to revert</span>
<span class="sd"> :type recipe_name: str</span>
<span class="sd"> :param commit: Commit hash</span>
<span class="sd"> :type commit: str</span>
<span class="sd"> :returns: OId of the new commit</span>
<span class="sd"> :rtype: Git.OId</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">revert_file</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe_filename</span><span class="p">(</span><span class="n">recipe_name</span><span class="p">),</span> <span class="n">commit</span><span class="p">)</span></div>
<div class="viewcode-block" id="revert_file"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.revert_file">[docs]</a><span class="k">def</span> <span class="nf">revert_file</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="n">commit</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Revert the contents of a file to that of a previous commit</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param filename: filename to revert</span>
<span class="sd"> :type filename: str</span>
<span class="sd"> :param commit: Commit hash</span>
<span class="sd"> :type commit: str</span>
<span class="sd"> :returns: OId of the new commit</span>
<span class="sd"> :rtype: Git.OId</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">commit_id</span> <span class="o">=</span> <span class="n">Git</span><span class="o">.</span><span class="n">OId</span><span class="o">.</span><span class="n">new_from_string</span><span class="p">(</span><span class="n">commit</span><span class="p">)</span>
<span class="n">commit_obj</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">commit_id</span><span class="p">,</span> <span class="n">Git</span><span class="o">.</span><span class="n">Commit</span><span class="p">)</span>
<span class="n">revert_tree</span> <span class="o">=</span> <span class="n">commit_obj</span><span class="o">.</span><span class="n">get_tree</span><span class="p">()</span>
<span class="n">entry</span> <span class="o">=</span> <span class="n">revert_tree</span><span class="o">.</span><span class="n">get_by_name</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
<span class="n">blob_id</span> <span class="o">=</span> <span class="n">entry</span><span class="o">.</span><span class="n">get_id</span><span class="p">()</span>
<span class="n">parent_commit</span> <span class="o">=</span> <span class="n">head_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">)</span>
<span class="c1"># Use treebuilder to modify the tree</span>
<span class="n">parent_tree</span> <span class="o">=</span> <span class="n">parent_commit</span><span class="o">.</span><span class="n">get_tree</span><span class="p">()</span>
<span class="n">builder</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">create_tree_builder_from_tree</span><span class="p">(</span><span class="n">parent_tree</span><span class="p">)</span>
<span class="n">builder</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">blob_id</span><span class="p">,</span> <span class="n">Git</span><span class="o">.</span><span class="n">FileMode</span><span class="o">.</span><span class="n">BLOB</span><span class="p">)</span>
<span class="p">(</span><span class="n">tree</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="n">ref</span><span class="p">)</span> <span class="o">=</span> <span class="n">prepare_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">builder</span><span class="p">)</span>
<span class="n">commit_hash</span> <span class="o">=</span> <span class="n">commit_id</span><span class="o">.</span><span class="n">to_string</span><span class="p">()</span>
<span class="n">message</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%s</span><span class="s2"> reverted to commit </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">commit_hash</span><span class="p">)</span>
<span class="k">return</span> <span class="n">repo</span><span class="o">.</span><span class="n">create_commit</span><span class="p">(</span><span class="n">ref</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="s2">&quot;UTF-8&quot;</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">tree</span><span class="p">,</span> <span class="p">[</span><span class="n">parent_commit</span><span class="p">])</span></div>
<div class="viewcode-block" id="commit_recipe"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.commit_recipe">[docs]</a><span class="k">def</span> <span class="nf">commit_recipe</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Commit a recipe to a branch</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param recipe: Recipe to commit</span>
<span class="sd"> :type recipe: Recipe</span>
<span class="sd"> :returns: OId of the new commit</span>
<span class="sd"> :rtype: Git.OId</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">old_recipe</span> <span class="o">=</span> <span class="n">read_recipe_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">])</span>
<span class="n">old_version</span> <span class="o">=</span> <span class="n">old_recipe</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">]</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<span class="n">old_version</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">recipe</span><span class="o">.</span><span class="n">bump_version</span><span class="p">(</span><span class="n">old_version</span><span class="p">)</span>
<span class="n">recipe_toml</span> <span class="o">=</span> <span class="n">recipe</span><span class="o">.</span><span class="n">toml</span><span class="p">()</span>
<span class="n">message</span> <span class="o">=</span> <span class="s2">&quot;Recipe </span><span class="si">%s</span><span class="s2">, version </span><span class="si">%s</span><span class="s2"> saved.&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">recipe</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">],</span> <span class="n">recipe</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">])</span>
<span class="k">return</span> <span class="n">write_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe</span><span class="o">.</span><span class="n">filename</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">recipe_toml</span><span class="p">)</span></div>
<div class="viewcode-block" id="commit_recipe_file"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.commit_recipe_file">[docs]</a><span class="k">def</span> <span class="nf">commit_recipe_file</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Commit a recipe file to a branch</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param filename: Path to the recipe file to commit</span>
<span class="sd"> :type filename: str</span>
<span class="sd"> :returns: OId of the new commit</span>
<span class="sd"> :rtype: Git.OId</span>
<span class="sd"> :raises: Can raise errors from Ggit or RecipeFileError</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">recipe</span> <span class="o">=</span> <span class="n">recipe_from_file</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">IOError</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">RecipeFileError</span>
<span class="k">return</span> <span class="n">commit_recipe</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe</span><span class="p">)</span></div>
<div class="viewcode-block" id="commit_recipe_directory"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.commit_recipe_directory">[docs]</a><span class="k">def</span> <span class="nf">commit_recipe_directory</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">directory</span><span class="p">):</span>
<span class="sa">r</span><span class="sd">&quot;&quot;&quot;Commit all \*.toml files from a directory, if they aren&#39;t already in git.</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param directory: The directory of \*.toml recipes to commit</span>
<span class="sd"> :type directory: str</span>
<span class="sd"> :returns: None</span>
<span class="sd"> :raises: Can raise errors from Ggit or RecipeFileError</span>
<span class="sd"> Files with Toml or RecipeFileErrors will be skipped, and the remainder will</span>
<span class="sd"> be tried.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">dir_files</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([</span><span class="n">e</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">directory</span><span class="p">)</span> <span class="k">if</span> <span class="n">e</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">&quot;.toml&quot;</span><span class="p">)])</span>
<span class="n">branch_files</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">list_branch_files</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">))</span>
<span class="n">new_files</span> <span class="o">=</span> <span class="n">dir_files</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">branch_files</span><span class="p">)</span>
<span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">new_files</span><span class="p">:</span>
<span class="c1"># Skip files with errors, but try the others</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">commit_recipe_file</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">directory</span><span class="p">,</span> <span class="n">f</span><span class="p">))</span>
<span class="k">except</span> <span class="p">(</span><span class="n">RecipeFileError</span><span class="p">,</span> <span class="n">toml</span><span class="o">.</span><span class="n">TomlError</span><span class="p">):</span>
<span class="k">pass</span></div>
<div class="viewcode-block" id="tag_recipe_commit"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.tag_recipe_commit">[docs]</a><span class="k">def</span> <span class="nf">tag_recipe_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe_name</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Tag a file&#39;s most recent commit</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param recipe_name: Recipe name to tag</span>
<span class="sd"> :type recipe_name: str</span>
<span class="sd"> :returns: Tag id or None if it failed.</span>
<span class="sd"> :rtype: Git.OId</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> Uses tag_file_commit()</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">repo_file_exists</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe_filename</span><span class="p">(</span><span class="n">recipe_name</span><span class="p">)):</span>
<span class="k">raise</span> <span class="n">RecipeFileError</span><span class="p">(</span><span class="s2">&quot;Unknown blueprint&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">tag_file_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">recipe_filename</span><span class="p">(</span><span class="n">recipe_name</span><span class="p">))</span></div>
<div class="viewcode-block" id="tag_file_commit"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.tag_file_commit">[docs]</a><span class="k">def</span> <span class="nf">tag_file_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Tag a file&#39;s most recent commit</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param filename: Filename to tag</span>
<span class="sd"> :type filename: str</span>
<span class="sd"> :returns: Tag id or None if it failed.</span>
<span class="sd"> :rtype: Git.OId</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> This uses git tags, of the form `refs/tags/&lt;branch&gt;/&lt;filename&gt;/r&lt;revision&gt;`</span>
<span class="sd"> Only the most recent recipe commit can be tagged to prevent out of order tagging.</span>
<span class="sd"> Revisions start at 1 and increment for each new commit that is tagged.</span>
<span class="sd"> If the commit has already been tagged it will return false.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">file_commits</span> <span class="o">=</span> <span class="n">list_commits</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">file_commits</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="c1"># Find the most recently tagged version (may not be one) and add 1 to it.</span>
<span class="k">for</span> <span class="n">details</span> <span class="ow">in</span> <span class="n">file_commits</span><span class="p">:</span>
<span class="k">if</span> <span class="n">details</span><span class="o">.</span><span class="n">revision</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">new_revision</span> <span class="o">=</span> <span class="n">details</span><span class="o">.</span><span class="n">revision</span> <span class="o">+</span> <span class="mi">1</span>
<span class="k">break</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">new_revision</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%s</span><span class="s2">/</span><span class="si">%s</span><span class="s2">/r</span><span class="si">%d</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">branch</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="n">new_revision</span><span class="p">)</span>
<span class="n">sig</span> <span class="o">=</span> <span class="n">Git</span><span class="o">.</span><span class="n">Signature</span><span class="o">.</span><span class="n">new_now</span><span class="p">(</span><span class="s2">&quot;bdcs-api-server&quot;</span><span class="p">,</span> <span class="s2">&quot;user-email&quot;</span><span class="p">)</span>
<span class="n">commit_id</span> <span class="o">=</span> <span class="n">Git</span><span class="o">.</span><span class="n">OId</span><span class="o">.</span><span class="n">new_from_string</span><span class="p">(</span><span class="n">file_commits</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">commit</span><span class="p">)</span>
<span class="n">commit</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">commit_id</span><span class="p">,</span> <span class="n">Git</span><span class="o">.</span><span class="n">Commit</span><span class="p">)</span>
<span class="k">return</span> <span class="n">repo</span><span class="o">.</span><span class="n">create_tag</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">commit</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">Git</span><span class="o">.</span><span class="n">CreateFlags</span><span class="o">.</span><span class="n">NONE</span><span class="p">)</span></div>
<div class="viewcode-block" id="find_commit_tag"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.find_commit_tag">[docs]</a><span class="k">def</span> <span class="nf">find_commit_tag</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="n">commit_id</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Find the tag that matches the commit_id</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param filename: filename to revert</span>
<span class="sd"> :type filename: str</span>
<span class="sd"> :param commit_id: The commit id to check</span>
<span class="sd"> :type commit_id: Git.OId</span>
<span class="sd"> :returns: The tag or None if there isn&#39;t one</span>
<span class="sd"> :rtype: str or None</span>
<span class="sd"> There should be only 1 tag pointing to a commit, but there may not</span>
<span class="sd"> be a tag at all.</span>
<span class="sd"> The tag will look like: &#39;refs/tags/&lt;branch&gt;/&lt;filename&gt;/r&lt;revision&gt;&#39;</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">pattern</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%s</span><span class="s2">/</span><span class="si">%s</span><span class="s2">/r*&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">branch</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
<span class="n">tags</span> <span class="o">=</span> <span class="p">[</span><span class="n">t</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">repo</span><span class="o">.</span><span class="n">list_tags_match</span><span class="p">(</span><span class="n">pattern</span><span class="p">)</span> <span class="k">if</span> <span class="n">is_commit_tag</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">commit_id</span><span class="p">,</span> <span class="n">t</span><span class="p">)]</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">tags</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">tags</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span></div>
<div class="viewcode-block" id="is_commit_tag"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.is_commit_tag">[docs]</a><span class="k">def</span> <span class="nf">is_commit_tag</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">commit_id</span><span class="p">,</span> <span class="n">tag</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Check to see if a tag points to a specific commit.</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param commit_id: The commit id to check</span>
<span class="sd"> :type commit_id: Git.OId</span>
<span class="sd"> :param tag: The tag to check</span>
<span class="sd"> :type tag: str</span>
<span class="sd"> :returns: True if the tag points to the commit, False otherwise</span>
<span class="sd"> :rtype: bool</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">ref</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">lookup_reference</span><span class="p">(</span><span class="s2">&quot;refs/tags/&quot;</span> <span class="o">+</span> <span class="n">tag</span><span class="p">)</span>
<span class="n">tag_id</span> <span class="o">=</span> <span class="n">ref</span><span class="o">.</span><span class="n">get_target</span><span class="p">()</span>
<span class="n">tag</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">tag_id</span><span class="p">,</span> <span class="n">Git</span><span class="o">.</span><span class="n">Tag</span><span class="p">)</span>
<span class="n">target_id</span> <span class="o">=</span> <span class="n">tag</span><span class="o">.</span><span class="n">get_target_id</span><span class="p">()</span>
<span class="k">return</span> <span class="n">commit_id</span><span class="o">.</span><span class="n">compare</span><span class="p">(</span><span class="n">target_id</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span></div>
<div class="viewcode-block" id="get_revision_from_tag"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.get_revision_from_tag">[docs]</a><span class="k">def</span> <span class="nf">get_revision_from_tag</span><span class="p">(</span><span class="n">tag</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return the revision number from a tag</span>
<span class="sd"> :param tag: The tag to exract the revision from</span>
<span class="sd"> :type tag: str</span>
<span class="sd"> :returns: The integer revision or None</span>
<span class="sd"> :rtype: int or None</span>
<span class="sd"> The revision is the part after the r in &#39;branch/filename/rXXX&#39;</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">tag</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">tag</span><span class="o">.</span><span class="n">rsplit</span><span class="p">(</span><span class="s1">&#39;r&#39;</span><span class="p">,</span> <span class="mi">2</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
<span class="k">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">IndexError</span><span class="p">):</span>
<span class="k">return</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="CommitDetails"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.CommitDetails">[docs]</a><span class="k">class</span> <span class="nc">CommitDetails</span><span class="p">(</span><span class="n">DataHolder</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">commit</span><span class="p">,</span> <span class="n">timestamp</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">revision</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="n">DataHolder</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
<span class="n">commit</span> <span class="o">=</span> <span class="n">commit</span><span class="p">,</span>
<span class="n">timestamp</span> <span class="o">=</span> <span class="n">timestamp</span><span class="p">,</span>
<span class="n">message</span> <span class="o">=</span> <span class="n">message</span><span class="p">,</span>
<span class="n">revision</span> <span class="o">=</span> <span class="n">revision</span><span class="p">)</span></div>
<div class="viewcode-block" id="list_commits"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.list_commits">[docs]</a><span class="k">def</span> <span class="nf">list_commits</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="n">limit</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;List the commit history of a file on a branch.</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param filename: filename to revert</span>
<span class="sd"> :type filename: str</span>
<span class="sd"> :param limit: Number of commits to return (0=all)</span>
<span class="sd"> :type limit: int</span>
<span class="sd"> :returns: A list of commit details</span>
<span class="sd"> :rtype: list(CommitDetails)</span>
<span class="sd"> :raises: Can raise errors from Ggit</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">revwalk</span> <span class="o">=</span> <span class="n">Git</span><span class="o">.</span><span class="n">RevisionWalker</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">repo</span><span class="p">)</span>
<span class="n">branch_ref</span> <span class="o">=</span> <span class="s2">&quot;refs/heads/</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">branch</span>
<span class="n">revwalk</span><span class="o">.</span><span class="n">push_ref</span><span class="p">(</span><span class="n">branch_ref</span><span class="p">)</span>
<span class="n">commits</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="n">commit_id</span> <span class="o">=</span> <span class="n">revwalk</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">commit_id</span><span class="p">:</span>
<span class="k">break</span>
<span class="n">commit</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">commit_id</span><span class="p">,</span> <span class="n">Git</span><span class="o">.</span><span class="n">Commit</span><span class="p">)</span>
<span class="n">parents</span> <span class="o">=</span> <span class="n">commit</span><span class="o">.</span><span class="n">get_parents</span><span class="p">()</span>
<span class="c1"># No parents? Must be the first commit.</span>
<span class="k">if</span> <span class="n">parents</span><span class="o">.</span><span class="n">get_size</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">continue</span>
<span class="n">tree</span> <span class="o">=</span> <span class="n">commit</span><span class="o">.</span><span class="n">get_tree</span><span class="p">()</span>
<span class="c1"># Is the filename in this tree? If not, move on.</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">tree</span><span class="o">.</span><span class="n">get_by_name</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
<span class="k">continue</span>
<span class="c1"># Is filename different in all of the parent commits?</span>
<span class="n">parent_commits</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="n">parents</span><span class="o">.</span><span class="n">get</span><span class="p">,</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">parents</span><span class="o">.</span><span class="n">get_size</span><span class="p">())))</span>
<span class="n">is_diff</span> <span class="o">=</span> <span class="nb">all</span><span class="p">([</span><span class="n">is_parent_diff</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="n">tree</span><span class="p">,</span> <span class="n">pc</span><span class="p">)</span> <span class="k">for</span> <span class="n">pc</span> <span class="ow">in</span> <span class="n">parent_commits</span><span class="p">])</span>
<span class="c1"># No changes from parents, skip it.</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">is_diff</span><span class="p">:</span>
<span class="k">continue</span>
<span class="n">tag</span> <span class="o">=</span> <span class="n">find_commit_tag</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="n">commit</span><span class="o">.</span><span class="n">get_id</span><span class="p">())</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">commits</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">get_commit_details</span><span class="p">(</span><span class="n">commit</span><span class="p">,</span> <span class="n">get_revision_from_tag</span><span class="p">(</span><span class="n">tag</span><span class="p">)))</span>
<span class="k">if</span> <span class="n">limit</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">commits</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">limit</span><span class="p">:</span>
<span class="k">break</span>
<span class="k">except</span> <span class="n">CommitTimeValError</span><span class="p">:</span>
<span class="c1"># Skip any commits that have trouble converting the time</span>
<span class="c1"># TODO - log details about this failure</span>
<span class="k">pass</span>
<span class="c1"># These will be in reverse time sort order thanks to revwalk</span>
<span class="k">return</span> <span class="n">commits</span></div>
<div class="viewcode-block" id="get_commit_details"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.get_commit_details">[docs]</a><span class="k">def</span> <span class="nf">get_commit_details</span><span class="p">(</span><span class="n">commit</span><span class="p">,</span> <span class="n">revision</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return the details about a specific commit.</span>
<span class="sd"> :param commit: The commit to get details from</span>
<span class="sd"> :type commit: Git.Commit</span>
<span class="sd"> :param revision: Optional commit revision</span>
<span class="sd"> :type revision: int</span>
<span class="sd"> :returns: Details about the commit</span>
<span class="sd"> :rtype: CommitDetails</span>
<span class="sd"> :raises: CommitTimeValError or Ggit exceptions</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">message</span> <span class="o">=</span> <span class="n">commit</span><span class="o">.</span><span class="n">get_message</span><span class="p">()</span>
<span class="n">commit_str</span> <span class="o">=</span> <span class="n">commit</span><span class="o">.</span><span class="n">get_id</span><span class="p">()</span><span class="o">.</span><span class="n">to_string</span><span class="p">()</span>
<span class="n">sig</span> <span class="o">=</span> <span class="n">commit</span><span class="o">.</span><span class="n">get_committer</span><span class="p">()</span>
<span class="n">datetime</span> <span class="o">=</span> <span class="n">sig</span><span class="o">.</span><span class="n">get_time</span><span class="p">()</span>
<span class="c1"># XXX What do we do with timezone?</span>
<span class="n">_timezone</span> <span class="o">=</span> <span class="n">sig</span><span class="o">.</span><span class="n">get_time_zone</span><span class="p">()</span>
<span class="n">timeval</span> <span class="o">=</span> <span class="n">GLib</span><span class="o">.</span><span class="n">TimeVal</span><span class="p">()</span>
<span class="n">ok</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">to_timeval</span><span class="p">(</span><span class="n">timeval</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">ok</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">CommitTimeValError</span>
<span class="n">time_str</span> <span class="o">=</span> <span class="n">timeval</span><span class="o">.</span><span class="n">to_iso8601</span><span class="p">()</span>
<span class="k">return</span> <span class="n">CommitDetails</span><span class="p">(</span><span class="n">commit_str</span><span class="p">,</span> <span class="n">time_str</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">revision</span><span class="p">)</span></div>
<div class="viewcode-block" id="is_parent_diff"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.is_parent_diff">[docs]</a><span class="k">def</span> <span class="nf">is_parent_diff</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="n">tree</span><span class="p">,</span> <span class="n">parent</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Check to see if the commit is different from its parents</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param filename: filename to revert</span>
<span class="sd"> :type filename: str</span>
<span class="sd"> :param tree: The commit&#39;s tree</span>
<span class="sd"> :type tree: Git.Tree</span>
<span class="sd"> :param parent: The commit&#39;s parent commit</span>
<span class="sd"> :type parent: Git.Commit</span>
<span class="sd"> :retuns: True if filename in the commit is different from its parents</span>
<span class="sd"> :rtype: bool</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">diff_opts</span> <span class="o">=</span> <span class="n">Git</span><span class="o">.</span><span class="n">DiffOptions</span><span class="o">.</span><span class="n">new</span><span class="p">()</span>
<span class="n">diff_opts</span><span class="o">.</span><span class="n">set_pathspec</span><span class="p">([</span><span class="n">filename</span><span class="p">])</span>
<span class="n">diff</span> <span class="o">=</span> <span class="n">Git</span><span class="o">.</span><span class="n">Diff</span><span class="o">.</span><span class="n">new_tree_to_tree</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">parent</span><span class="o">.</span><span class="n">get_tree</span><span class="p">(),</span> <span class="n">tree</span><span class="p">,</span> <span class="n">diff_opts</span><span class="p">)</span>
<span class="k">return</span> <span class="n">diff</span><span class="o">.</span><span class="n">get_num_deltas</span><span class="p">()</span> <span class="o">&gt;</span> <span class="mi">0</span></div>
<div class="viewcode-block" id="find_field_value"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.find_field_value">[docs]</a><span class="k">def</span> <span class="nf">find_field_value</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">lst</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Find a field matching value in the list of dicts.</span>
<span class="sd"> :param field: field to search for</span>
<span class="sd"> :type field: str</span>
<span class="sd"> :param value: value to match in the field</span>
<span class="sd"> :type value: str</span>
<span class="sd"> :param lst: List of dict&#39;s with field</span>
<span class="sd"> :type lst: list of dict</span>
<span class="sd"> :returns: First dict with matching field:value, or None</span>
<span class="sd"> :rtype: dict or None</span>
<span class="sd"> Used to return a specific entry from a list that looks like this:</span>
<span class="sd"> [{&quot;name&quot;: &quot;one&quot;, &quot;attr&quot;: &quot;green&quot;}, ...]</span>
<span class="sd"> find_field_value(&quot;name&quot;, &quot;one&quot;, lst) will return the matching dict.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">lst</span><span class="p">:</span>
<span class="k">if</span> <span class="n">d</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">field</span><span class="p">)</span> <span class="ow">and</span> <span class="n">d</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">field</span><span class="p">)</span> <span class="o">==</span> <span class="n">value</span><span class="p">:</span>
<span class="k">return</span> <span class="n">d</span>
<span class="k">return</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="find_name"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.find_name">[docs]</a><span class="k">def</span> <span class="nf">find_name</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">lst</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Find the dict matching the name in a list and return it.</span>
<span class="sd"> :param name: Name to search for</span>
<span class="sd"> :type name: str</span>
<span class="sd"> :param lst: List of dict&#39;s with &quot;name&quot; field</span>
<span class="sd"> :type lst: list of dict</span>
<span class="sd"> :returns: First dict with matching name, or None</span>
<span class="sd"> :rtype: dict or None</span>
<span class="sd"> This is just a wrapper for find_field_value with field set to &quot;name&quot;</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">find_field_value</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">lst</span><span class="p">)</span></div>
<div class="viewcode-block" id="find_recipe_obj"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.find_recipe_obj">[docs]</a><span class="k">def</span> <span class="nf">find_recipe_obj</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">recipe</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Find a recipe object</span>
<span class="sd"> :param path: A list of dict field names</span>
<span class="sd"> :type path: list of str</span>
<span class="sd"> :param recipe: The recipe to search</span>
<span class="sd"> :type recipe: Recipe</span>
<span class="sd"> :param default: The value to return if it is not found</span>
<span class="sd"> :type default: Any</span>
<span class="sd"> Return the object found by applying the path to the dicts in the recipe, or</span>
<span class="sd"> return the default if it doesn&#39;t exist.</span>
<span class="sd"> eg. {&quot;customizations&quot;: {&quot;hostname&quot;: &quot;foo&quot;, &quot;users&quot;: [...]}}</span>
<span class="sd"> find_recipe_obj([&quot;customizations&quot;, &quot;hostname&quot;], recipe, &quot;&quot;)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">o</span> <span class="o">=</span> <span class="n">recipe</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">path</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">o</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">p</span><span class="p">):</span>
<span class="k">return</span> <span class="n">default</span>
<span class="n">o</span> <span class="o">=</span> <span class="n">o</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
<span class="k">return</span> <span class="n">default</span>
<span class="k">return</span> <span class="n">o</span></div>
<div class="viewcode-block" id="diff_lists"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.diff_lists">[docs]</a><span class="k">def</span> <span class="nf">diff_lists</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">field</span><span class="p">,</span> <span class="n">old_items</span><span class="p">,</span> <span class="n">new_items</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return the differences between two lists of dicts.</span>
<span class="sd"> :param title: Title of the entry</span>
<span class="sd"> :type title: str</span>
<span class="sd"> :param field: Field to use as the key for comparisons</span>
<span class="sd"> :type field: str</span>
<span class="sd"> :param old_items: List of item dicts with &quot;name&quot; field</span>
<span class="sd"> :type old_items: list(dict)</span>
<span class="sd"> :param new_items: List of item dicts with &quot;name&quot; field</span>
<span class="sd"> :type new_items: list(dict)</span>
<span class="sd"> :returns: List of diff dicts with old/new entries</span>
<span class="sd"> :rtype: list(dict)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">diffs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">old_fields</span><span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">m</span><span class="p">[</span><span class="n">field</span><span class="p">]</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">old_items</span><span class="p">)</span>
<span class="n">new_fields</span><span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">m</span><span class="p">[</span><span class="n">field</span><span class="p">]</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">new_items</span><span class="p">)</span>
<span class="n">added_items</span> <span class="o">=</span> <span class="n">new_fields</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">old_fields</span><span class="p">)</span>
<span class="n">added_items</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">added_items</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span>
<span class="n">removed_items</span> <span class="o">=</span> <span class="n">old_fields</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">new_fields</span><span class="p">)</span>
<span class="n">removed_items</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">removed_items</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span>
<span class="n">same_items</span> <span class="o">=</span> <span class="n">old_fields</span><span class="o">.</span><span class="n">intersection</span><span class="p">(</span><span class="n">new_fields</span><span class="p">)</span>
<span class="n">same_items</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">same_items</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span>
<span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">added_items</span><span class="p">:</span>
<span class="n">diffs</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s2">&quot;old&quot;</span><span class="p">:</span><span class="kc">None</span><span class="p">,</span>
<span class="s2">&quot;new&quot;</span><span class="p">:{</span><span class="n">title</span><span class="p">:</span><span class="n">find_field_value</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">new_items</span><span class="p">)}})</span>
<span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">removed_items</span><span class="p">:</span>
<span class="n">diffs</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s2">&quot;old&quot;</span><span class="p">:{</span><span class="n">title</span><span class="p">:</span><span class="n">find_field_value</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">old_items</span><span class="p">)},</span>
<span class="s2">&quot;new&quot;</span><span class="p">:</span><span class="kc">None</span><span class="p">})</span>
<span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">same_items</span><span class="p">:</span>
<span class="n">old_item</span> <span class="o">=</span> <span class="n">find_field_value</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">old_items</span><span class="p">)</span>
<span class="n">new_item</span> <span class="o">=</span> <span class="n">find_field_value</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">new_items</span><span class="p">)</span>
<span class="k">if</span> <span class="n">old_item</span> <span class="o">!=</span> <span class="n">new_item</span><span class="p">:</span>
<span class="n">diffs</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s2">&quot;old&quot;</span><span class="p">:{</span><span class="n">title</span><span class="p">:</span><span class="n">old_item</span><span class="p">},</span>
<span class="s2">&quot;new&quot;</span><span class="p">:{</span><span class="n">title</span><span class="p">:</span><span class="n">new_item</span><span class="p">}})</span>
<span class="k">return</span> <span class="n">diffs</span></div>
<div class="viewcode-block" id="customizations_diff"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.customizations_diff">[docs]</a><span class="k">def</span> <span class="nf">customizations_diff</span><span class="p">(</span><span class="n">old_recipe</span><span class="p">,</span> <span class="n">new_recipe</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Diff the customizations sections from two versions of a recipe</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">diffs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">old_keys</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">old_recipe</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;customizations&quot;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
<span class="n">new_keys</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">new_recipe</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;customizations&quot;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
<span class="n">added_keys</span> <span class="o">=</span> <span class="n">new_keys</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">old_keys</span><span class="p">)</span>
<span class="n">added_keys</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">added_keys</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span>
<span class="n">removed_keys</span> <span class="o">=</span> <span class="n">old_keys</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">new_keys</span><span class="p">)</span>
<span class="n">removed_keys</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">removed_keys</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span>
<span class="n">same_keys</span> <span class="o">=</span> <span class="n">old_keys</span><span class="o">.</span><span class="n">intersection</span><span class="p">(</span><span class="n">new_keys</span><span class="p">)</span>
<span class="n">same_keys</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">same_keys</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span>
<span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">added_keys</span><span class="p">:</span>
<span class="n">diffs</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s2">&quot;old&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
<span class="s2">&quot;new&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;Customizations.&quot;</span><span class="o">+</span><span class="n">v</span><span class="p">:</span> <span class="n">new_recipe</span><span class="p">[</span><span class="s2">&quot;customizations&quot;</span><span class="p">][</span><span class="n">v</span><span class="p">]}})</span>
<span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">removed_keys</span><span class="p">:</span>
<span class="n">diffs</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s2">&quot;old&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;Customizations.&quot;</span><span class="o">+</span><span class="n">v</span><span class="p">:</span> <span class="n">old_recipe</span><span class="p">[</span><span class="s2">&quot;customizations&quot;</span><span class="p">][</span><span class="n">v</span><span class="p">]},</span>
<span class="s2">&quot;new&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">})</span>
<span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">same_keys</span><span class="p">:</span>
<span class="k">if</span> <span class="n">new_recipe</span><span class="p">[</span><span class="s2">&quot;customizations&quot;</span><span class="p">][</span><span class="n">v</span><span class="p">]</span> <span class="o">==</span> <span class="n">old_recipe</span><span class="p">[</span><span class="s2">&quot;customizations&quot;</span><span class="p">][</span><span class="n">v</span><span class="p">]:</span>
<span class="k">continue</span>
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">new_recipe</span><span class="p">[</span><span class="s2">&quot;customizations&quot;</span><span class="p">][</span><span class="n">v</span><span class="p">])</span> <span class="o">==</span> <span class="nb">type</span><span class="p">([]):</span>
<span class="c1"># Lists of dicts need to use diff_lists</span>
<span class="c1"># sshkey uses &#39;user&#39;, user and group use &#39;name&#39;</span>
<span class="k">if</span> <span class="s2">&quot;user&quot;</span> <span class="ow">in</span> <span class="n">new_recipe</span><span class="p">[</span><span class="s2">&quot;customizations&quot;</span><span class="p">][</span><span class="n">v</span><span class="p">][</span><span class="mi">0</span><span class="p">]:</span>
<span class="n">field_name</span> <span class="o">=</span> <span class="s2">&quot;user&quot;</span>
<span class="k">elif</span> <span class="s2">&quot;name&quot;</span> <span class="ow">in</span> <span class="n">new_recipe</span><span class="p">[</span><span class="s2">&quot;customizations&quot;</span><span class="p">][</span><span class="n">v</span><span class="p">][</span><span class="mi">0</span><span class="p">]:</span>
<span class="n">field_name</span> <span class="o">=</span> <span class="s2">&quot;name&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">%s</span><span class="s2"> list has unrecognized key, not &#39;name&#39; or &#39;user&#39;&quot;</span> <span class="o">%</span> <span class="s2">&quot;customizations.&quot;</span><span class="o">+</span><span class="n">v</span><span class="p">)</span>
<span class="n">diffs</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">diff_lists</span><span class="p">(</span><span class="s2">&quot;Customizations.&quot;</span><span class="o">+</span><span class="n">v</span><span class="p">,</span> <span class="n">field_name</span><span class="p">,</span> <span class="n">old_recipe</span><span class="p">[</span><span class="s2">&quot;customizations&quot;</span><span class="p">][</span><span class="n">v</span><span class="p">],</span> <span class="n">new_recipe</span><span class="p">[</span><span class="s2">&quot;customizations&quot;</span><span class="p">][</span><span class="n">v</span><span class="p">]))</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">diffs</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s2">&quot;old&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;Customizations.&quot;</span><span class="o">+</span><span class="n">v</span><span class="p">:</span> <span class="n">old_recipe</span><span class="p">[</span><span class="s2">&quot;customizations&quot;</span><span class="p">][</span><span class="n">v</span><span class="p">]},</span>
<span class="s2">&quot;new&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;Customizations.&quot;</span><span class="o">+</span><span class="n">v</span><span class="p">:</span> <span class="n">new_recipe</span><span class="p">[</span><span class="s2">&quot;customizations&quot;</span><span class="p">][</span><span class="n">v</span><span class="p">]}})</span>
<span class="k">return</span> <span class="n">diffs</span></div>
<div class="viewcode-block" id="recipe_diff"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.recipe_diff">[docs]</a><span class="k">def</span> <span class="nf">recipe_diff</span><span class="p">(</span><span class="n">old_recipe</span><span class="p">,</span> <span class="n">new_recipe</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Diff two versions of a recipe</span>
<span class="sd"> :param old_recipe: The old version of the recipe</span>
<span class="sd"> :type old_recipe: Recipe</span>
<span class="sd"> :param new_recipe: The new version of the recipe</span>
<span class="sd"> :type new_recipe: Recipe</span>
<span class="sd"> :returns: A list of diff dict entries with old/new</span>
<span class="sd"> :rtype: list(dict)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">diffs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="c1"># These cannot be added or removed, just different</span>
<span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">,</span> <span class="s2">&quot;description&quot;</span><span class="p">,</span> <span class="s2">&quot;version&quot;</span><span class="p">]:</span>
<span class="k">if</span> <span class="n">old_recipe</span><span class="p">[</span><span class="n">element</span><span class="p">]</span> <span class="o">!=</span> <span class="n">new_recipe</span><span class="p">[</span><span class="n">element</span><span class="p">]:</span>
<span class="n">diffs</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s2">&quot;old&quot;</span><span class="p">:{</span><span class="n">element</span><span class="o">.</span><span class="n">title</span><span class="p">():</span><span class="n">old_recipe</span><span class="p">[</span><span class="n">element</span><span class="p">]},</span>
<span class="s2">&quot;new&quot;</span><span class="p">:{</span><span class="n">element</span><span class="o">.</span><span class="n">title</span><span class="p">():</span><span class="n">new_recipe</span><span class="p">[</span><span class="n">element</span><span class="p">]}})</span>
<span class="c1"># These lists always exist</span>
<span class="n">diffs</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">diff_lists</span><span class="p">(</span><span class="s2">&quot;Module&quot;</span><span class="p">,</span> <span class="s2">&quot;name&quot;</span><span class="p">,</span> <span class="n">old_recipe</span><span class="p">[</span><span class="s2">&quot;modules&quot;</span><span class="p">],</span> <span class="n">new_recipe</span><span class="p">[</span><span class="s2">&quot;modules&quot;</span><span class="p">]))</span>
<span class="n">diffs</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">diff_lists</span><span class="p">(</span><span class="s2">&quot;Package&quot;</span><span class="p">,</span> <span class="s2">&quot;name&quot;</span><span class="p">,</span> <span class="n">old_recipe</span><span class="p">[</span><span class="s2">&quot;packages&quot;</span><span class="p">],</span> <span class="n">new_recipe</span><span class="p">[</span><span class="s2">&quot;packages&quot;</span><span class="p">]))</span>
<span class="n">diffs</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">diff_lists</span><span class="p">(</span><span class="s2">&quot;Group&quot;</span><span class="p">,</span> <span class="s2">&quot;name&quot;</span><span class="p">,</span> <span class="n">old_recipe</span><span class="p">[</span><span class="s2">&quot;groups&quot;</span><span class="p">],</span> <span class="n">new_recipe</span><span class="p">[</span><span class="s2">&quot;groups&quot;</span><span class="p">]))</span>
<span class="c1"># The customizations section can contain a number of different types</span>
<span class="n">diffs</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">customizations_diff</span><span class="p">(</span><span class="n">old_recipe</span><span class="p">,</span> <span class="n">new_recipe</span><span class="p">))</span>
<span class="c1"># repos contains keys that are lists (eg. [[repos.git]])</span>
<span class="n">diffs</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">diff_lists</span><span class="p">(</span><span class="s2">&quot;Repos.git&quot;</span><span class="p">,</span> <span class="s2">&quot;rpmname&quot;</span><span class="p">,</span>
<span class="n">find_recipe_obj</span><span class="p">([</span><span class="s2">&quot;repos&quot;</span><span class="p">,</span> <span class="s2">&quot;git&quot;</span><span class="p">],</span> <span class="n">old_recipe</span><span class="p">,</span> <span class="p">[]),</span>
<span class="n">find_recipe_obj</span><span class="p">([</span><span class="s2">&quot;repos&quot;</span><span class="p">,</span> <span class="s2">&quot;git&quot;</span><span class="p">],</span> <span class="n">new_recipe</span><span class="p">,</span> <span class="p">[])))</span>
<span class="k">return</span> <span class="n">diffs</span></div>
<div class="viewcode-block" id="repo_file_exists"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.recipes.repo_file_exists">[docs]</a><span class="k">def</span> <span class="nf">repo_file_exists</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Return True if the filename exists on the branch</span>
<span class="sd"> :param repo: Open repository</span>
<span class="sd"> :type repo: Git.Repository</span>
<span class="sd"> :param branch: Branch name</span>
<span class="sd"> :type branch: str</span>
<span class="sd"> :param filename: Filename to check</span>
<span class="sd"> :type filename: str</span>
<span class="sd"> :returns: True if the filename exists on the HEAD of the branch, False otherwise.</span>
<span class="sd"> :rtype: bool</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">commit</span> <span class="o">=</span> <span class="n">head_commit</span><span class="p">(</span><span class="n">repo</span><span class="p">,</span> <span class="n">branch</span><span class="p">)</span><span class="o">.</span><span class="n">get_id</span><span class="p">()</span><span class="o">.</span><span class="n">to_string</span><span class="p">()</span>
<span class="n">commit_id</span> <span class="o">=</span> <span class="n">Git</span><span class="o">.</span><span class="n">OId</span><span class="o">.</span><span class="n">new_from_string</span><span class="p">(</span><span class="n">commit</span><span class="p">)</span>
<span class="n">commit_obj</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">commit_id</span><span class="p">,</span> <span class="n">Git</span><span class="o">.</span><span class="n">Commit</span><span class="p">)</span>
<span class="n">tree</span> <span class="o">=</span> <span class="n">commit_obj</span><span class="o">.</span><span class="n">get_tree</span><span class="p">()</span>
<span class="k">return</span> <span class="n">tree</span><span class="o">.</span><span class="n">get_by_name</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span></div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>
&copy; Copyright 2018-2019, Red Hat, Inc.
</p>
</div>
Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/rtfd/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script type="text/javascript">
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>