<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Marc-Antoine Perennou, Author at Clever Cloud</title>
	<atom:link href="https://www.clever.cloud/blog/author/marc-antoine-perennouclever-cloud-com/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>From Code to Product</description>
	<lastBuildDate>Thu, 23 Oct 2025 14:09:05 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://cdn.clever-cloud.com/uploads/2023/03/cropped-cropped-favicon-32x32.png</url>
	<title>Marc-Antoine Perennou, Author at Clever Cloud</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>One Framework a Day keeps the Boredom Away: Sinatra</title>
		<link>https://www.clever.cloud/blog/features/2017/10/16/1fdba-sinatra/</link>
		
		<dc:creator><![CDATA[Marc-Antoine Perennou]]></dc:creator>
		<pubDate>Mon, 16 Oct 2017 17:15:00 +0000</pubDate>
				<category><![CDATA[Features]]></category>
		<category><![CDATA[1fdba]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[puma]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[sinatra]]></category>
		<guid isPermaLink="false">https://www2.cleverapps.io/wp/blog/technology/2017/10/16/1fdba-sinatra/</guid>

					<description><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/1fdba-sinatra-1.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="1fdba sinatra 1" decoding="async" fetchpriority="high" srcset="https://cdn.clever-cloud.com/uploads/2021/08/1fdba-sinatra-1.png 1400w, https://cdn.clever-cloud.com/uploads/2021/08/1fdba-sinatra-1-300x116.png 300w, https://cdn.clever-cloud.com/uploads/2021/08/1fdba-sinatra-1-1024x395.png 1024w, https://cdn.clever-cloud.com/uploads/2021/08/1fdba-sinatra-1-768x296.png 768w, https://cdn.clever-cloud.com/uploads/2021/08/1fdba-sinatra-1-1368x528.png 1368w" sizes="(max-width: 1400px) 100vw, 1400px" /></p><p>Welcome to this new edition of <a href="/blog/features/2017/10/09/1fdba-step0/">One Framework a Day keeps the Boredom Away</a>. In this series I will show you how to deploy a particular framework on Clever Cloud every day until I want to go back to boredom. Today it&#39;s about Sinatra.</p>
<span id="more-2910"></span>

<p>In each post of this series we&#39;ll see how to deploy a particular framework on Clever Cloud. Today we are taking a look at <a href="http://www.sinatrarb.com/">Sinatra</a>.</p>
<p>If you want to tag along, make sure you have git, a Clever Cloud account and that you have installed our CLI <a href="https://github.com/CleverCloud/clever-tools">Clever-Tools</a>.</p>
<h2 id="what-is-sinatra">What is Sinatra?</h2>
<blockquote>
Sinatra is a DSL for quickly creating web applications in Ruby with minimal effort
</blockquote>

<p>It&#39;s been around for 10 years now and has already inspired several other framework since then. Ratpack which was <a href="/blog/features/2017/10/12/ratpack/">showcased last week</a> has been heavily inspired by sinatra for instance.  Our own <a href="https://twitter.com/Keruspe/">Keruspe</a> wanted to play with a couple of Ruby technologies like Puma and Sinatra. And so he built a <a href="https://github.com/CleverCloud/demo-sinatra-puma-activerecord">sample project</a> for it. That&#39;s what we are going to deploy today.</p>
<h2 id="setup">Setup</h2>
<ul>
<li>Start by cloning the sources: <code>git clone https://github.com/CleverCloud/demo-sinatra-puma-activerecord</code></li>
<li>Create the database you want to use, in my case Postgres: <code>clever addon create postgresql-addon --plan dev --region eu sinatraPG</code></li>
<li>Create the Ruby application on Clever Cloud: <code>clever create --type ruby sinatraSample --region par</code></li>
<li>Link the Postgres add-on to the application: <code>clever service link-addon sinatraPG</code></li>
<li>Tell Clever Cloud to deploy the API using puma (the default is uwsgi as of now): <code>clever env set CC_RACKUP_SERVER puma</code></li>
<li>Tell Clever Cloud to run database migrations before launching the API:<code>clever env set CC_PRE_RUN_HOOK &#39;bundle exec rake db:migrate&#39;</code></li>
<li>Add a domain name: <code>clever domain add mySinatraSample.cleverapps.io</code></li>
</ul>
<p>Specify the maximum number of PG connections your application will use (depending on the selected plan) by adding an environment variable like <code>DB_POOL=5</code> if you want to use 5 connections. For production, you should also set:</p>
<pre><code class="language-bash">clever env set RACK_ENV production
clever env set RAILS_ENV production
</code></pre>
<h2 id="deploy">Deploy</h2>
<ul>
<li>Deploy the application with <code>clever deploy</code></li>
</ul>
<p>And you are up and running. This application provides an API to store users. They only have a name field. Users can be created with a POST request and retrieve with a GET request like so:  </p>
<ul>
<li>Create an object with <code>curl --data &quot;regis&quot;  https://mySinatraSample.cleverapps.io</code></li>
<li>Retrieve that object with <code>curl https://mySinatraSample.cleverapps.io/regis</code></li>
</ul>
<p>Everything works out of the box because this application has been written for Clever Cloud. If you take a look at the condfiguration file under <code>./config/database.yml</code> you should see some environment variables being used. They are the one provided by our Postgres add-on. You can get the full list of variables with <code>clever env</code>.</p>
<p>Let us know your thoughts on this in the comments below. We will be back tomorrow for another post :)</p>
]]></description>
										<content:encoded><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/1fdba-sinatra-1.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="1fdba sinatra 1" decoding="async" srcset="https://cdn.clever-cloud.com/uploads/2021/08/1fdba-sinatra-1.png 1400w, https://cdn.clever-cloud.com/uploads/2021/08/1fdba-sinatra-1-300x116.png 300w, https://cdn.clever-cloud.com/uploads/2021/08/1fdba-sinatra-1-1024x395.png 1024w, https://cdn.clever-cloud.com/uploads/2021/08/1fdba-sinatra-1-768x296.png 768w, https://cdn.clever-cloud.com/uploads/2021/08/1fdba-sinatra-1-1368x528.png 1368w" sizes="(max-width: 1400px) 100vw, 1400px" /></p><p>Welcome to this new edition of <a href="/blog/features/2017/10/09/1fdba-step0/">One Framework a Day keeps the Boredom Away</a>. In this series I will show you how to deploy a particular framework on Clever Cloud every day until I want to go back to boredom. Today it&#39;s about Sinatra.</p>
<span id="more-2910"></span>

<p>In each post of this series we&#39;ll see how to deploy a particular framework on Clever Cloud. Today we are taking a look at <a href="http://www.sinatrarb.com/">Sinatra</a>.</p>
<p>If you want to tag along, make sure you have git, a Clever Cloud account and that you have installed our CLI <a href="https://github.com/CleverCloud/clever-tools">Clever-Tools</a>.</p>
<h2 id="what-is-sinatra">What is Sinatra?</h2>
<blockquote>
Sinatra is a DSL for quickly creating web applications in Ruby with minimal effort
</blockquote>

<p>It&#39;s been around for 10 years now and has already inspired several other framework since then. Ratpack which was <a href="/blog/features/2017/10/12/ratpack/">showcased last week</a> has been heavily inspired by sinatra for instance.  Our own <a href="https://twitter.com/Keruspe/">Keruspe</a> wanted to play with a couple of Ruby technologies like Puma and Sinatra. And so he built a <a href="https://github.com/CleverCloud/demo-sinatra-puma-activerecord">sample project</a> for it. That&#39;s what we are going to deploy today.</p>
<h2 id="setup">Setup</h2>
<ul>
<li>Start by cloning the sources: <code>git clone https://github.com/CleverCloud/demo-sinatra-puma-activerecord</code></li>
<li>Create the database you want to use, in my case Postgres: <code>clever addon create postgresql-addon --plan dev --region eu sinatraPG</code></li>
<li>Create the Ruby application on Clever Cloud: <code>clever create --type ruby sinatraSample --region par</code></li>
<li>Link the Postgres add-on to the application: <code>clever service link-addon sinatraPG</code></li>
<li>Tell Clever Cloud to deploy the API using puma (the default is uwsgi as of now): <code>clever env set CC_RACKUP_SERVER puma</code></li>
<li>Tell Clever Cloud to run database migrations before launching the API:<code>clever env set CC_PRE_RUN_HOOK &#39;bundle exec rake db:migrate&#39;</code></li>
<li>Add a domain name: <code>clever domain add mySinatraSample.cleverapps.io</code></li>
</ul>
<p>Specify the maximum number of PG connections your application will use (depending on the selected plan) by adding an environment variable like <code>DB_POOL=5</code> if you want to use 5 connections. For production, you should also set:</p>
<pre><code class="language-bash">clever env set RACK_ENV production
clever env set RAILS_ENV production
</code></pre>
<h2 id="deploy">Deploy</h2>
<ul>
<li>Deploy the application with <code>clever deploy</code></li>
</ul>
<p>And you are up and running. This application provides an API to store users. They only have a name field. Users can be created with a POST request and retrieve with a GET request like so:  </p>
<ul>
<li>Create an object with <code>curl --data &quot;regis&quot;  https://mySinatraSample.cleverapps.io</code></li>
<li>Retrieve that object with <code>curl https://mySinatraSample.cleverapps.io/regis</code></li>
</ul>
<p>Everything works out of the box because this application has been written for Clever Cloud. If you take a look at the condfiguration file under <code>./config/database.yml</code> you should see some environment variables being used. They are the one provided by our Postgres add-on. You can get the full list of variables with <code>clever env</code>.</p>
<p>Let us know your thoughts on this in the comments below. We will be back tomorrow for another post :)</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Rust packaging on Exherbo</title>
		<link>https://www.clever.cloud/blog/engineering/2016/10/24/exherbo-rust-packaging/</link>
		
		<dc:creator><![CDATA[Marc-Antoine Perennou]]></dc:creator>
		<pubDate>Mon, 24 Oct 2016 14:36:00 +0000</pubDate>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[exherbo]]></category>
		<category><![CDATA[Rust]]></category>
		<guid isPermaLink="false">https://www2.cleverapps.io/wp/blog/technology/2016/10/24/exherbo-rust-packaging/</guid>

					<description><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/rust-packaging-1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="rust packaging 1" decoding="async" srcset="https://cdn.clever-cloud.com/uploads/2021/08/rust-packaging-1.jpg 1400w, https://cdn.clever-cloud.com/uploads/2021/08/rust-packaging-1-300x116.jpg 300w, https://cdn.clever-cloud.com/uploads/2021/08/rust-packaging-1-1024x395.jpg 1024w, https://cdn.clever-cloud.com/uploads/2021/08/rust-packaging-1-768x296.jpg 768w, https://cdn.clever-cloud.com/uploads/2021/08/rust-packaging-1-1368x528.jpg 1368w" sizes="(max-width: 1400px) 100vw, 1400px" /></p><p>At Clever Cloud, we love giving new technologies a try. Since its inception, <a href="http://rust-lang.org/">rust</a> has always been quite appealing and we always wanted to find projects for which rust would be an adequate solution.</p>
<p>Now that rust is mature enough (to our taste), we started giving it a go, and we needed a way to easily package rust software for our distribution of choice: <a href="https://exherbo.org/">Exherbo</a>.</p>
<span id="more-2808"></span>

<h2 id="rust-package-manager-cargo">Rust package manager: cargo</h2>
<p>Amongst the tooling shipped with rust is cargo. Cargo allows you to simply build, test and install a package and its dependencies. It&#39;s actually very nice to use when developing.</p>
<p>If we were to install software with cargo, there are two solutions:</p>
<ul>
<li>Either we want to install something like a private or local projects and we just
have to go to the sources directory, where the <code>Cargo.toml</code> file is, and run
<code>cargo install</code></li>
<li>Or we want to install something publicly available, on <a href="https://crates.io/">crates.io</a>
for example, we can just run <code>cargo install crate_name</code>, <code>crate_name</code> being the actual
crate (cargo package) name. We could also pass it a git URL as an alternative.</li>
</ul>
<p>Regarding production environment and system-wide utilities, we want everything to be managed by the distribution package manager, <a href="http://paludis.exherbo.org/">paludis</a>, so we had to hook up those two and try to make them work together as well as possible.</p>
<h2 id="how-packaging-rust-is-different-from-packaging-other-software">How packaging rust is different from packaging other software</h2>
<p>Currently, rust doesn&#39;t support installing libraries system-wide as they&#39;re not confident enough in the stability of their <a href="https://en.wikipedia.org/wiki/Application_binary_interface">ABI</a> yet. What that concretely means is that it&#39;s not yet possible to install any rust library, and then use it to build dependent stuff. You have to rebuild all the dependencies each time you build a rust binary.</p>
<p>That particular point is the most noticeable difference on the packaging point of view. Instead of building and installing the dependencies, then the dependents, you only install the final product with everything built in.</p>
<h2 id="what-a-traditional-install-process-looks-like-in-a-source-based-distribution">What a &quot;traditional&quot; install process looks like in a source-based distribution</h2>
<p>For traditional packages, the build and install process is composed of several sequential steps, that we can summarize like this, in that order:</p>
<h3 id="fetch">Fetch</h3>
<p>This is the step where we download everything, usually the software sources.</p>
<p>This is the only step for which network sandboxing is disabled.</p>
<h3 id="unpack">Unpack</h3>
<p>Here we unpack the sources in a sandboxed environment. Network sandboxing is on as well as file system sandboxing for this step and all the steps onwards.</p>
<h3 id="prepare">Prepare</h3>
<p>This is an optional phase, not needed by all packages. It&#39;s the moment when we generate build-system files if needed and apply patches to the software sources.</p>
<h3 id="configure">Configure</h3>
<p>We decide there which features we want to enable or not for the build.</p>
<h3 id="build">Build</h3>
<p>Where the actual build happens.</p>
<h3 id="install">Install</h3>
<p>We install the resulting binaries/files in a sandboxed location replicating the / hierarchy.</p>
<h3 id="merge">Merge</h3>
<p>Once everything gets validated in terms of file system access, everything gets installed to the root file system.</p>
<h2 id="what-a-rust-install-process-looks-like">What a rust install process looks like</h2>
<p>A rust install pretty much ressembles a traditional one, with one huge exception.</p>
<p>As I said before, <code>cargo install</code> supports either reading a local <code>Cargo.toml</code>, or being passed a crate name or a git URL.</p>
<p>On the other hand, <code>cargo fetch</code>, which is the command that downloads all the dependencies doesn&#39;t have these options, it only supports reading a local <code>Cargo.toml</code> and fetching the dependencies listed in it. If libraries were installable system-wide, we wouldn&#39;t need this step at all, but since they&#39;re not, we <em>have</em> to do this step <em>after</em> unpacking the sources, to be able to access the <code>Cargo.toml</code>.</p>
<p>This has serious implications, it means that we extend the unpack phase with three additional actions:</p>
<ul>
<li>disable the network sandboxing, which is really sad and we should never do that</li>
<li><code>cargo fecth</code></li>
<li>re-enable the network sandboxing</li>
</ul>
<p>Of course, we don&#39;t have to download the dependencies at each reinstall, cargo supports a <code>CARGO_HOME</code> environment variable allowing us to store the downloads in a shared location with all other distfiles.</p>
<p>We&#39;ll eventually be able to install libraries system-wide, but I don&#39;t see that happening any time soon. The better workaround I could come up with to clean up this hack is to make <code>cargo fetch</code> support being given a crate name or a URL, matching its companion <code>cargo install</code>. <a href="https://github.com/rust-lang/cargo/issues/2998">Here is the corresponding github issue</a> but I&#39;m not sure whether it will be implemented nor when.</p>
<h2 id="actual-implementation-and-examples">Actual implementation and examples</h2>
<p>The implementation of my exlib (which is to exherbo packages what libraries are to software) <a href="https://git.exherbo.org/rust.git/tree/exlibs/cargo.exlib">can be found here</a>.</p>
<p><a href="https://git.exherbo.org/rust.git/tree/packages/dev-rust/cargo-watch/cargo-watch-3.1.0.exheres-0?id=1feab03e51d7419e5fcea3f6348c396fa795a66e">cargo-watch</a> is a good example of what a rust exherbo package using this exlib looks like. You can see it&#39;s fairly trivial and everything is automatic.</p>
]]></description>
										<content:encoded><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/rust-packaging-1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="rust packaging 1" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2021/08/rust-packaging-1.jpg 1400w, https://cdn.clever-cloud.com/uploads/2021/08/rust-packaging-1-300x116.jpg 300w, https://cdn.clever-cloud.com/uploads/2021/08/rust-packaging-1-1024x395.jpg 1024w, https://cdn.clever-cloud.com/uploads/2021/08/rust-packaging-1-768x296.jpg 768w, https://cdn.clever-cloud.com/uploads/2021/08/rust-packaging-1-1368x528.jpg 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p><p>At Clever Cloud, we love giving new technologies a try. Since its inception, <a href="http://rust-lang.org/">rust</a> has always been quite appealing and we always wanted to find projects for which rust would be an adequate solution.</p>
<p>Now that rust is mature enough (to our taste), we started giving it a go, and we needed a way to easily package rust software for our distribution of choice: <a href="https://exherbo.org/">Exherbo</a>.</p>
<span id="more-2808"></span>

<h2 id="rust-package-manager-cargo">Rust package manager: cargo</h2>
<p>Amongst the tooling shipped with rust is cargo. Cargo allows you to simply build, test and install a package and its dependencies. It&#39;s actually very nice to use when developing.</p>
<p>If we were to install software with cargo, there are two solutions:</p>
<ul>
<li>Either we want to install something like a private or local projects and we just
have to go to the sources directory, where the <code>Cargo.toml</code> file is, and run
<code>cargo install</code></li>
<li>Or we want to install something publicly available, on <a href="https://crates.io/">crates.io</a>
for example, we can just run <code>cargo install crate_name</code>, <code>crate_name</code> being the actual
crate (cargo package) name. We could also pass it a git URL as an alternative.</li>
</ul>
<p>Regarding production environment and system-wide utilities, we want everything to be managed by the distribution package manager, <a href="http://paludis.exherbo.org/">paludis</a>, so we had to hook up those two and try to make them work together as well as possible.</p>
<h2 id="how-packaging-rust-is-different-from-packaging-other-software">How packaging rust is different from packaging other software</h2>
<p>Currently, rust doesn&#39;t support installing libraries system-wide as they&#39;re not confident enough in the stability of their <a href="https://en.wikipedia.org/wiki/Application_binary_interface">ABI</a> yet. What that concretely means is that it&#39;s not yet possible to install any rust library, and then use it to build dependent stuff. You have to rebuild all the dependencies each time you build a rust binary.</p>
<p>That particular point is the most noticeable difference on the packaging point of view. Instead of building and installing the dependencies, then the dependents, you only install the final product with everything built in.</p>
<h2 id="what-a-traditional-install-process-looks-like-in-a-source-based-distribution">What a &quot;traditional&quot; install process looks like in a source-based distribution</h2>
<p>For traditional packages, the build and install process is composed of several sequential steps, that we can summarize like this, in that order:</p>
<h3 id="fetch">Fetch</h3>
<p>This is the step where we download everything, usually the software sources.</p>
<p>This is the only step for which network sandboxing is disabled.</p>
<h3 id="unpack">Unpack</h3>
<p>Here we unpack the sources in a sandboxed environment. Network sandboxing is on as well as file system sandboxing for this step and all the steps onwards.</p>
<h3 id="prepare">Prepare</h3>
<p>This is an optional phase, not needed by all packages. It&#39;s the moment when we generate build-system files if needed and apply patches to the software sources.</p>
<h3 id="configure">Configure</h3>
<p>We decide there which features we want to enable or not for the build.</p>
<h3 id="build">Build</h3>
<p>Where the actual build happens.</p>
<h3 id="install">Install</h3>
<p>We install the resulting binaries/files in a sandboxed location replicating the / hierarchy.</p>
<h3 id="merge">Merge</h3>
<p>Once everything gets validated in terms of file system access, everything gets installed to the root file system.</p>
<h2 id="what-a-rust-install-process-looks-like">What a rust install process looks like</h2>
<p>A rust install pretty much ressembles a traditional one, with one huge exception.</p>
<p>As I said before, <code>cargo install</code> supports either reading a local <code>Cargo.toml</code>, or being passed a crate name or a git URL.</p>
<p>On the other hand, <code>cargo fetch</code>, which is the command that downloads all the dependencies doesn&#39;t have these options, it only supports reading a local <code>Cargo.toml</code> and fetching the dependencies listed in it. If libraries were installable system-wide, we wouldn&#39;t need this step at all, but since they&#39;re not, we <em>have</em> to do this step <em>after</em> unpacking the sources, to be able to access the <code>Cargo.toml</code>.</p>
<p>This has serious implications, it means that we extend the unpack phase with three additional actions:</p>
<ul>
<li>disable the network sandboxing, which is really sad and we should never do that</li>
<li><code>cargo fecth</code></li>
<li>re-enable the network sandboxing</li>
</ul>
<p>Of course, we don&#39;t have to download the dependencies at each reinstall, cargo supports a <code>CARGO_HOME</code> environment variable allowing us to store the downloads in a shared location with all other distfiles.</p>
<p>We&#39;ll eventually be able to install libraries system-wide, but I don&#39;t see that happening any time soon. The better workaround I could come up with to clean up this hack is to make <code>cargo fetch</code> support being given a crate name or a URL, matching its companion <code>cargo install</code>. <a href="https://github.com/rust-lang/cargo/issues/2998">Here is the corresponding github issue</a> but I&#39;m not sure whether it will be implemented nor when.</p>
<h2 id="actual-implementation-and-examples">Actual implementation and examples</h2>
<p>The implementation of my exlib (which is to exherbo packages what libraries are to software) <a href="https://git.exherbo.org/rust.git/tree/exlibs/cargo.exlib">can be found here</a>.</p>
<p><a href="https://git.exherbo.org/rust.git/tree/packages/dev-rust/cargo-watch/cargo-watch-3.1.0.exheres-0?id=1feab03e51d7419e5fcea3f6348c396fa795a66e">cargo-watch</a> is a good example of what a rust exherbo package using this exlib looks like. You can see it&#39;s fairly trivial and everything is automatic.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How Facebook Infer Can Make your Software Safer</title>
		<link>https://www.clever.cloud/blog/engineering/2015/06/22/fb-infer-safer-code/</link>
		
		<dc:creator><![CDATA[Marc-Antoine Perennou]]></dc:creator>
		<pubDate>Mon, 22 Jun 2015 17:05:00 +0000</pubDate>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[compilation]]></category>
		<category><![CDATA[static-analysis]]></category>
		<guid isPermaLink="false">https://www2.cleverapps.io/wp/blog/technology/2015/06/22/fb-infer-safer-code/</guid>

					<description><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/fb-infer-1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="fb infer 1" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2021/08/fb-infer-1.jpg 1400w, https://cdn.clever-cloud.com/uploads/2021/08/fb-infer-1-300x116.jpg 300w, https://cdn.clever-cloud.com/uploads/2021/08/fb-infer-1-1024x395.jpg 1024w, https://cdn.clever-cloud.com/uploads/2021/08/fb-infer-1-768x296.jpg 768w, https://cdn.clever-cloud.com/uploads/2021/08/fb-infer-1-1368x528.jpg 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p><p>At Clever Cloud, we like giving a try to new technologies when they&#39;re released, especially if it means safer software. When facebook <a href="https://code.facebook.com/posts/1648953042007882/open-sourcing-facebook-infer-identify-bugs-before-you-ship/">recently announced</a> the release of <a href="http://fbinfer.com/">infer</a>, we surely wanted to try it out!</p>
<span id="more-2801"></span>

<h3 id="the-concept-of-static-analysis">The concept of static analysis</h3>
<p>The idea behind infer is quite simple: it analyses your code before you actually run it and looks for common code issues or misconceptions which can lead to unsafe code.</p>
<p>You can think of it as some kind of compiler plugin which will do some stricter checks and produce more warnings than your compiler usually does.</p>
<p>The idea of static analysis is really great as you get to know some of your code&#39;s problems before even trying to run it. An issue with most static analyzers though is the false positives, those warnings you know shouldn&#39;t be there as you perfectly know that this problem is 100% impossible to happen.</p>
<h3 id="testing-our-code-with-infer">Testing our code with infer</h3>
<p>We tend to use a lot of different technologies to run our platform. From the languages supported by infer, Java was the most interesting to us. I decided to run a first pass on all of our Java projects.</p>
<p>After getting <a href="https://github.com/facebook/infer">the code</a> on github and following the installation instructions in <code>INSTALL.md</code>, I started with one of our core small pieces of software.</p>
<p>I didn&#39;t expect to see many defects but was afraid of getting a ton of false positives when I ran the test: <code>infer -- mvn clean package</code>. Turned out we got a couple of legitimate warnings about resource leaks when spawning a process and then waiting for it but not destroying it once done, and nothing more! No false positives at all.</p>
<p>For the record, those warnings looked like that:</p>
<p><code>error: RESOURCE_LEAK resource acquired by call to exec(...) at line 89 is not released after line 89</code></p>
<p>Fix was as easy as changing <code>return Runtime.getRuntime().exec(cmd).waitFor();</code> to</p>
<pre><code class="language-java">Process p = Runtime.getRuntime().exec(cmd);
int res = p.waitFor();
p.destroy();
return res;
</code></pre>
<p>As the beginning was encouraging, I went on and ran it on one of our core libraries. One similar problem found, one potential null dereference in an error path and another resource leak warning. The first two were trivial to fix, the last one was a weird one as in some cases it didn&#39;t detect a stream to be closed. After refactoring this piece of code which was quite old, the warning was gone, but what appeared to me as being a false positive frightened me when it came to running it on our big API.</p>
<p>The relevant annoying warning: <code>error: RESOURCE_LEAK resource acquired by call to FileReaderHelper(...) at line 28 is not released after line 30</code></p>
<p>FileReaderHelper makes use of a BufferedReader; changing the scope of the inside reader fixed the issue.</p>
<p>Most of our other projects are really small and no defects were detected at all; then came our API. Our API is the oldest piece of software we&#39;re running. As time goes by, we externalise the codebase into separate projects but it&#39;s still quite a huge one with its 415 files.</p>
<p>Good surprise: only 20 defects, 18 of them in the same error path which would mean that our platform is unavailable anyways. Amongst the two others, one was clearly a false positive. I added an assertion to silence the warning with a comment explaining why it was there. But the warning wouldn&#39;t go. I&#39;ve since then opened <a href="https://github.com/facebook/infer/issues/68">an issue</a> for this which hopefully will be fixed soon.</p>
<p>An example of NULL pointer dereference for which we added checks because &quot;better safe than sorry&quot; when it really should never happen: <code>error: NULL_DEREFERENCE object returned by token.getUserId() could be null and is dereferenced at line 86</code></p>
<h3 id="conclusions">Conclusions</h3>
<p>Only two false positives in all of our codebase, and a couple of really pertinent warnings makes this project really promising. It doesn&#39;t throw a lot of warnings yet (or we didn&#39;t hit much) but it reduces the noise by giving only relevant ones and avoiding false positives, which is a really good thing for a static analyser.</p>
<p>With an integration into our CI, it&#39;ll now provide yet more guaranties about code safety.</p>
<p>Go and try it for yourself!</p>
]]></description>
										<content:encoded><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/fb-infer-1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="fb infer 1" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2021/08/fb-infer-1.jpg 1400w, https://cdn.clever-cloud.com/uploads/2021/08/fb-infer-1-300x116.jpg 300w, https://cdn.clever-cloud.com/uploads/2021/08/fb-infer-1-1024x395.jpg 1024w, https://cdn.clever-cloud.com/uploads/2021/08/fb-infer-1-768x296.jpg 768w, https://cdn.clever-cloud.com/uploads/2021/08/fb-infer-1-1368x528.jpg 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p><p>At Clever Cloud, we like giving a try to new technologies when they&#39;re released, especially if it means safer software. When facebook <a href="https://code.facebook.com/posts/1648953042007882/open-sourcing-facebook-infer-identify-bugs-before-you-ship/">recently announced</a> the release of <a href="http://fbinfer.com/">infer</a>, we surely wanted to try it out!</p>
<span id="more-2801"></span>

<h3 id="the-concept-of-static-analysis">The concept of static analysis</h3>
<p>The idea behind infer is quite simple: it analyses your code before you actually run it and looks for common code issues or misconceptions which can lead to unsafe code.</p>
<p>You can think of it as some kind of compiler plugin which will do some stricter checks and produce more warnings than your compiler usually does.</p>
<p>The idea of static analysis is really great as you get to know some of your code&#39;s problems before even trying to run it. An issue with most static analyzers though is the false positives, those warnings you know shouldn&#39;t be there as you perfectly know that this problem is 100% impossible to happen.</p>
<h3 id="testing-our-code-with-infer">Testing our code with infer</h3>
<p>We tend to use a lot of different technologies to run our platform. From the languages supported by infer, Java was the most interesting to us. I decided to run a first pass on all of our Java projects.</p>
<p>After getting <a href="https://github.com/facebook/infer">the code</a> on github and following the installation instructions in <code>INSTALL.md</code>, I started with one of our core small pieces of software.</p>
<p>I didn&#39;t expect to see many defects but was afraid of getting a ton of false positives when I ran the test: <code>infer -- mvn clean package</code>. Turned out we got a couple of legitimate warnings about resource leaks when spawning a process and then waiting for it but not destroying it once done, and nothing more! No false positives at all.</p>
<p>For the record, those warnings looked like that:</p>
<p><code>error: RESOURCE_LEAK resource acquired by call to exec(...) at line 89 is not released after line 89</code></p>
<p>Fix was as easy as changing <code>return Runtime.getRuntime().exec(cmd).waitFor();</code> to</p>
<pre><code class="language-java">Process p = Runtime.getRuntime().exec(cmd);
int res = p.waitFor();
p.destroy();
return res;
</code></pre>
<p>As the beginning was encouraging, I went on and ran it on one of our core libraries. One similar problem found, one potential null dereference in an error path and another resource leak warning. The first two were trivial to fix, the last one was a weird one as in some cases it didn&#39;t detect a stream to be closed. After refactoring this piece of code which was quite old, the warning was gone, but what appeared to me as being a false positive frightened me when it came to running it on our big API.</p>
<p>The relevant annoying warning: <code>error: RESOURCE_LEAK resource acquired by call to FileReaderHelper(...) at line 28 is not released after line 30</code></p>
<p>FileReaderHelper makes use of a BufferedReader; changing the scope of the inside reader fixed the issue.</p>
<p>Most of our other projects are really small and no defects were detected at all; then came our API. Our API is the oldest piece of software we&#39;re running. As time goes by, we externalise the codebase into separate projects but it&#39;s still quite a huge one with its 415 files.</p>
<p>Good surprise: only 20 defects, 18 of them in the same error path which would mean that our platform is unavailable anyways. Amongst the two others, one was clearly a false positive. I added an assertion to silence the warning with a comment explaining why it was there. But the warning wouldn&#39;t go. I&#39;ve since then opened <a href="https://github.com/facebook/infer/issues/68">an issue</a> for this which hopefully will be fixed soon.</p>
<p>An example of NULL pointer dereference for which we added checks because &quot;better safe than sorry&quot; when it really should never happen: <code>error: NULL_DEREFERENCE object returned by token.getUserId() could be null and is dereferenced at line 86</code></p>
<h3 id="conclusions">Conclusions</h3>
<p>Only two false positives in all of our codebase, and a couple of really pertinent warnings makes this project really promising. It doesn&#39;t throw a lot of warnings yet (or we didn&#39;t hit much) but it reduces the noise by giving only relevant ones and avoiding false positives, which is a really good thing for a static analyser.</p>
<p>With an integration into our CI, it&#39;ll now provide yet more guaranties about code safety.</p>
<p>Go and try it for yourself!</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How We Cut Latency Down by 30k% on Our Git Server</title>
		<link>https://www.clever.cloud/blog/engineering/2015/06/09/git-server-30k-improvement/</link>
		
		<dc:creator><![CDATA[Marc-Antoine Perennou]]></dc:creator>
		<pubDate>Tue, 09 Jun 2015 14:01:00 +0000</pubDate>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[performances]]></category>
		<guid isPermaLink="false">https://www2.cleverapps.io/wp/blog/technology/2015/06/09/git-server-30k-improvement/</guid>

					<description><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="ars perfs 1" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1.jpg 1400w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-300x116.jpg 300w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-1024x395.jpg 1024w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-768x296.jpg 768w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-1368x528.jpg 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p><p>At Clever Cloud, git is core in the deployment process. With the years, our needs evolved, especially in terms of performance. This is how we dealt with it.</p>
<span id="more-2800"></span>

<h3 id="a-bit-of-background-first">A bit of background first</h3>
<p>When we started Clever Cloud, we chose to use <a href="http://gitolite.com/gitolite/index.html">gitolite</a> to manage our git repositories. It appeared to be a complete and functional solution. We used it internally first, for managing our own internal repositories even when the product wasn&#39;t released yet.</p>
<p>After several months of testing, we were convinced that it was a really good solution, and chose to go with it.</p>
<h4 id="managing-gitolite-configuration">Managing gitolite configuration</h4>
<p>gitolite is primary designed to be configured manually by a sysadmin. You have to describe every user, group of users and repositories in configuration files. Gitolite will then use these files to generate its internal stuff for dealing with access rights. Gitolite ensures repositories are created and hooks propagated.</p>
<p>We were in the need of automatic reconfiguration, for quite obvious reasons. We therefore developed a tool called <code>etilotig</code> which aim was to keep gitolite&#39;s configuration up to date. On startup, this tool would load its initial configuration from the API and then listen to <a href="https://www.amqp.org/">AMQP</a> events to update its configuration cache and write the new gitolite configuration accordingly.</p>
<p>It worked actually quite well for longer than we expected, and we used it in production until May 5th 2015.</p>
<h3 id="the-drawbacks-of-gitolite">The drawbacks of gitolite</h3>
<p>gitolite was great but had a few major drawbacks we weren&#39;t happy with.</p>
<ul>
<li>as previously said, it wasn&#39;t meant to be dynamically configurable, which required some non-trivial hacks</li>
<li>it required duplicating the configuration in both the API and gitolite itself</li>
<li>all the repositories were created in a same directory</li>
<li>at each repository creation, it did a full pass on all the repositories to check whether the hooks were up to date
or not</li>
<li>rewriting only part of its configuration wasn&#39;t trivial at all so we ended up rewriting most of it for each change</li>
</ul>
<p>Those problems were annoying but not critical at the beginning, but some of them became quite interesting to us.</p>
<p>The fact that all repositories are created in a same directory is a huge performance issue when the number of repositories become really high.</p>
<p>We actually dropped the part that checks for the hooks at each repository creation from the gitolite code a while back as it took half the time of the gitolite internal configuration regeneration on update.</p>
<h3 id="the-new-etilotig">The new etilotig</h3>
<p>While gitolite used to be efficient, lately it had a lot of performance problems, and depending on the timing of the events, it could take up to five (!) minutes to create a new repository. This went far beyond our acceptable limits, so we had to find another solution.</p>
<p>The idea was simple: drop gitolite totally and improve our configuration management tool etilotig to do what was needed by itself.</p>
<p>The checklist we needed to accomplish was quite tiny:</p>
<ul>
<li>ssh keys management</li>
<li>authorization management</li>
<li>repositories creation</li>
<li>hooks installation</li>
</ul>
<h4 id="ssh-keys-management">Ssh keys management</h4>
<p>When its goal was only to manage the gitolite configuration, etilotig only forwarded them to gitolite, which in turn handled them. Now, we have to manage the <code>authorized_keys</code> file by ourselves.</p>
<p>We basically write a new one each time an ssh key is added or removed and then replace the old one with the new one.</p>
<p>Each line is printed as such:</p>
<pre><code class="language-text">command=&quot;AUTH_SCRIPT USER_ID&quot;,no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty PUBLIC_KEY
</code></pre>
<p>With <code>AUTH_SCRIPT</code> pointing to the authorization script that I&#39;ll speak of later, <code>USER_ID</code> being the user id of the key owner and <code>PUBLIC_KEY</code> being their public key.</p>
<p>The authorization script will thus be called with the user id as first parameter.</p>
<p>That solves the first point of our TODO list.</p>
<h4 id="repositories-management">Repositories management</h4>
<p>At startup, etilotig writes some bash configuration files defining basic things such as the directory in which repositories have to be created.</p>
<p>Then we have a tiny bash script in charge of the repository creation. We now create them in a deeper directory hierarchy to get as few repositories as possible per directory. Say we had <code>/data/app_18c6021b-0860-4f97-a08d-0663f45cf3f0.git</code> before, we now have <code>/data/app_18/c6/02/app_18c6021b-0860-4f97-a08d-0663f45cf3f0.git</code> which makes things waaaaay faster.</p>
<pre><code class="language-bash">#!/bin/bash

create_repo() {
local repo_dir=&quot;${1}&quot;

mkdir -p &quot;${repo_dir}&quot;
pushd &quot;${repo_dir}&quot; &amp;&gt;/dev/null
git init --bare
popd &amp;&gt;/dev/null
}

main() {
    local repo=&quot;${1}&quot;
    local repo_dir
    
repo_dir=&quot;${REPOS_DIR}/${repo:0:6}/${repo:6:2}/${repo:8:2}/${repo}&quot;

[[ -d &quot;${repo_dir}&quot;/hooks ]] || create_repo &quot;${repo_dir}&quot;
}

. &quot;${HOME}&quot;/.etilotig/.etilotigrc

main &quot;${@}&quot;
</code></pre>
<p>Then we have another one for hooks installation.</p>
<pre><code class="language-bash">#!/bin/bash

shopt -s nullglob

main() {
    local repo=&quot;${1}&quot;
    local repo_dir
    
repo_dir=&quot;${REPOS_DIR}/${repo:0:6}/${repo:6:2}/${repo:8:2}/${repo}&quot;

for hook in ${HOME}/.etilotig/hooks/*; do
ln -sf &quot;${hook}&quot; &quot;${repo_dir}&quot;/hooks/
done
}

. &quot;${HOME}&quot;/.etilotig/.etilotigrc

main &quot;${@}&quot;
</code></pre>
<p>With those two simple scripts, we only have to call them for each repository at startup to ensure everything is OK, and at each repository creation, which solves two of the four points from our TODO list, only one left.</p>
<h4 id="authorization">Authorization</h4>
<p>Now, the goal was <em>not</em> to duplicate the configuration anymore, but rather use the configuration from the API, thus externalising the whole thing. Dropping all the configuration management from etilotig reduced its size by more than 50%.</p>
<p>The way etilotig manages authorization is quite simple: when it generates its internal configuration, it actually generates a perl script which is called on each ssh connection attempt. The script then authorises or not the transaction.</p>
<p>We made a similar script which prints the users some information about which repositories they have access to if they just run <code>ssh git@push.par.clever-cloud.com</code> or such, checks if they are authorized when they try to git push/pull or rejects any other request.</p>
<p>It looks like this (with some extra stuff added):</p>
<pre><code class="language-bash">#!/bin/bash

sanity_check() {
    if [[ -z &quot;${SSH_CONNECTION}&quot; ]]; then
        echo &quot;Who the hell are you?&quot; &gt;&amp;2
        exit 1
    fi

if [[ -z &quot;${SSH_ORIGINAL_COMMAND}&quot; ]]; then
        export SSH_ORIGINAL_COMMAND=&quot;info&quot;
fi
}

ask_for_info() {
    local userid=&quot;${1}&quot;

# make the request to the API to retrieve user info message
echo &quot;some info&quot;
}

ask_for_authorization() {
    local userid=&quot;${1}&quot;
    local appid=&quot;${2}&quot;

# make the request and return the HTTP status code here. 200 means authorized.
echo 200
}

authorize() {
    local userid=&quot;${1}&quot;
    local verb=&quot;${2}&quot;
    local appid=&quot;${3}&quot;
    local ret=1
    case &quot;${verb}&quot; in
        &quot;git-receive-pack&quot;|&quot;git-upload-pack&quot;)
            local code
            code=$(ask_for_authorization &quot;${userid}&quot; &quot;${appid}&quot;)
            [[ &quot;${code}&quot; == &quot;200&quot; ]] &amp;&amp; ret=0
            ;;
    esac
    return &quot;${ret}&quot;
}

final_abort() {
    echo &quot;What are you trying to achieve here?&quot; &gt;&amp;2
    exit 2
}
main() {
    sanity_check
    local userid=&quot;${1}&quot;
    local verb
    local repo
    local repo_dir
    verb=$(echo &quot;${SSH_ORIGINAL_COMMAND}&quot; | cut -d &#39; &#39; -f 1)
    repo=$(echo &quot;${SSH_ORIGINAL_COMMAND}&quot; | cut -d &#39; &#39; -f 2 | tr -d &quot;&#39;\&quot;&quot;)
    [[ &quot;${repo}&quot; == /* ]] &amp;&amp; repo=${repo:1}
    repo_dir=&quot;${REPOS_DIR}/${repo:0:6}/${repo:6:2}/${repo:8:2}/${repo}&quot;
    if [[ &quot;${verb}&quot; == &quot;info&quot; ]]; then
        ask_for_info &quot;${userid}&quot;
    elif authorize &quot;${userid}&quot; &quot;${verb}&quot; &quot;${repo}&quot;; then
        export CC_USER=&quot;${userid}&quot;
        export CC_NOTIFY_SCRIPT=&quot;${HOME}/.etilotig/send-push-event&quot;
        exec &quot;${verb}&quot; &quot;${repo_dir}&quot;
    else
        final_abort
    fi
}
. &quot;${HOME}&quot;/.etilotig/.etilotigrc
main &quot;${@}&quot;
</code></pre>
<p>With this in place, nearly everything was ready. Two tiny hooks on top of that to only allow users to push on the master branch, and to trigger a deployment on git push:</p>
<p><code>hooks/update</code></p>
<pre><code class="language-bash">#!/bin/bash

main() {
    local rev=&quot;${1}&quot;
    if [[ &quot;${rev}&quot; == refs/tags/* ]]; then
        exit 0
    fi
    if [[ &quot;${rev}&quot; != &quot;refs/heads/master&quot; ]]; then
        echo &quot;You tried to push to a custom branch.&quot;
        echo &quot;Only master is allowed.&quot;
        exit 1
    fi
}

main &quot;${@}&quot;
</code></pre>
<p><code>hooks/post-update</code></p>
<pre><code class="language-bash">#!/bin/bash

sanity_check() {
    local rev=&quot;${1}&quot;
    if [[ &quot;${rev}&quot; == refs/tags/* ]]; then
        exit 0
    fi
}

main () {
    local rev=&quot;${1}&quot;
    sanity_check &quot;${rev}&quot;
    local repo=$(basename $(pwd))
    local appId=${repo/.git/}
    local commitId=$(git rev-parse &quot;${rev}&quot;)
    &quot;${CC_NOTIFY_SCRIPT}&quot; &quot;${appId}&quot; &quot;${commitId}&quot; &quot;${CC_USER}&quot;
    echo &quot;[SUCCESS] The application has successfully been queued for redeploy.&quot;
}

main &quot;${@}&quot;
</code></pre>
<h3 id="conclusion">Conclusion</h3>
<p>That&#39;s it, we have our new git server manager up and running, which works pretty well.</p>
<p>The performance gain? We went from between 3 and more than 5 minutes to less than 1 second per action, while dropping the whole gitolite codebase and reducing the size of etilotig by 50%, with an average performance gain of 30k%.</p>
<p>gitolite has been very useful both in its utilisation and its codebase to better comprehend the whole authentication mechanism, so a great thanks to this awesome tool.</p>
<p>Now gitolite is dead, long live etilotig!</p>
]]></description>
										<content:encoded><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="ars perfs 1" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1.jpg 1400w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-300x116.jpg 300w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-1024x395.jpg 1024w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-768x296.jpg 768w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-1368x528.jpg 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p><p>At Clever Cloud, git is core in the deployment process. With the years, our needs evolved, especially in terms of performance. This is how we dealt with it.</p>
<span id="more-2800"></span>

<h3 id="a-bit-of-background-first">A bit of background first</h3>
<p>When we started Clever Cloud, we chose to use <a href="http://gitolite.com/gitolite/index.html">gitolite</a> to manage our git repositories. It appeared to be a complete and functional solution. We used it internally first, for managing our own internal repositories even when the product wasn&#39;t released yet.</p>
<p>After several months of testing, we were convinced that it was a really good solution, and chose to go with it.</p>
<h4 id="managing-gitolite-configuration">Managing gitolite configuration</h4>
<p>gitolite is primary designed to be configured manually by a sysadmin. You have to describe every user, group of users and repositories in configuration files. Gitolite will then use these files to generate its internal stuff for dealing with access rights. Gitolite ensures repositories are created and hooks propagated.</p>
<p>We were in the need of automatic reconfiguration, for quite obvious reasons. We therefore developed a tool called <code>etilotig</code> which aim was to keep gitolite&#39;s configuration up to date. On startup, this tool would load its initial configuration from the API and then listen to <a href="https://www.amqp.org/">AMQP</a> events to update its configuration cache and write the new gitolite configuration accordingly.</p>
<p>It worked actually quite well for longer than we expected, and we used it in production until May 5th 2015.</p>
<h3 id="the-drawbacks-of-gitolite">The drawbacks of gitolite</h3>
<p>gitolite was great but had a few major drawbacks we weren&#39;t happy with.</p>
<ul>
<li>as previously said, it wasn&#39;t meant to be dynamically configurable, which required some non-trivial hacks</li>
<li>it required duplicating the configuration in both the API and gitolite itself</li>
<li>all the repositories were created in a same directory</li>
<li>at each repository creation, it did a full pass on all the repositories to check whether the hooks were up to date
or not</li>
<li>rewriting only part of its configuration wasn&#39;t trivial at all so we ended up rewriting most of it for each change</li>
</ul>
<p>Those problems were annoying but not critical at the beginning, but some of them became quite interesting to us.</p>
<p>The fact that all repositories are created in a same directory is a huge performance issue when the number of repositories become really high.</p>
<p>We actually dropped the part that checks for the hooks at each repository creation from the gitolite code a while back as it took half the time of the gitolite internal configuration regeneration on update.</p>
<h3 id="the-new-etilotig">The new etilotig</h3>
<p>While gitolite used to be efficient, lately it had a lot of performance problems, and depending on the timing of the events, it could take up to five (!) minutes to create a new repository. This went far beyond our acceptable limits, so we had to find another solution.</p>
<p>The idea was simple: drop gitolite totally and improve our configuration management tool etilotig to do what was needed by itself.</p>
<p>The checklist we needed to accomplish was quite tiny:</p>
<ul>
<li>ssh keys management</li>
<li>authorization management</li>
<li>repositories creation</li>
<li>hooks installation</li>
</ul>
<h4 id="ssh-keys-management">Ssh keys management</h4>
<p>When its goal was only to manage the gitolite configuration, etilotig only forwarded them to gitolite, which in turn handled them. Now, we have to manage the <code>authorized_keys</code> file by ourselves.</p>
<p>We basically write a new one each time an ssh key is added or removed and then replace the old one with the new one.</p>
<p>Each line is printed as such:</p>
<pre><code class="language-text">command=&quot;AUTH_SCRIPT USER_ID&quot;,no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty PUBLIC_KEY
</code></pre>
<p>With <code>AUTH_SCRIPT</code> pointing to the authorization script that I&#39;ll speak of later, <code>USER_ID</code> being the user id of the key owner and <code>PUBLIC_KEY</code> being their public key.</p>
<p>The authorization script will thus be called with the user id as first parameter.</p>
<p>That solves the first point of our TODO list.</p>
<h4 id="repositories-management">Repositories management</h4>
<p>At startup, etilotig writes some bash configuration files defining basic things such as the directory in which repositories have to be created.</p>
<p>Then we have a tiny bash script in charge of the repository creation. We now create them in a deeper directory hierarchy to get as few repositories as possible per directory. Say we had <code>/data/app_18c6021b-0860-4f97-a08d-0663f45cf3f0.git</code> before, we now have <code>/data/app_18/c6/02/app_18c6021b-0860-4f97-a08d-0663f45cf3f0.git</code> which makes things waaaaay faster.</p>
<pre><code class="language-bash">#!/bin/bash

create_repo() {
local repo_dir=&quot;${1}&quot;

mkdir -p &quot;${repo_dir}&quot;
pushd &quot;${repo_dir}&quot; &amp;&gt;/dev/null
git init --bare
popd &amp;&gt;/dev/null
}

main() {
    local repo=&quot;${1}&quot;
    local repo_dir
    
repo_dir=&quot;${REPOS_DIR}/${repo:0:6}/${repo:6:2}/${repo:8:2}/${repo}&quot;

[[ -d &quot;${repo_dir}&quot;/hooks ]] || create_repo &quot;${repo_dir}&quot;
}

. &quot;${HOME}&quot;/.etilotig/.etilotigrc

main &quot;${@}&quot;
</code></pre>
<p>Then we have another one for hooks installation.</p>
<pre><code class="language-bash">#!/bin/bash

shopt -s nullglob

main() {
    local repo=&quot;${1}&quot;
    local repo_dir
    
repo_dir=&quot;${REPOS_DIR}/${repo:0:6}/${repo:6:2}/${repo:8:2}/${repo}&quot;

for hook in ${HOME}/.etilotig/hooks/*; do
ln -sf &quot;${hook}&quot; &quot;${repo_dir}&quot;/hooks/
done
}

. &quot;${HOME}&quot;/.etilotig/.etilotigrc

main &quot;${@}&quot;
</code></pre>
<p>With those two simple scripts, we only have to call them for each repository at startup to ensure everything is OK, and at each repository creation, which solves two of the four points from our TODO list, only one left.</p>
<h4 id="authorization">Authorization</h4>
<p>Now, the goal was <em>not</em> to duplicate the configuration anymore, but rather use the configuration from the API, thus externalising the whole thing. Dropping all the configuration management from etilotig reduced its size by more than 50%.</p>
<p>The way etilotig manages authorization is quite simple: when it generates its internal configuration, it actually generates a perl script which is called on each ssh connection attempt. The script then authorises or not the transaction.</p>
<p>We made a similar script which prints the users some information about which repositories they have access to if they just run <code>ssh git@push.par.clever-cloud.com</code> or such, checks if they are authorized when they try to git push/pull or rejects any other request.</p>
<p>It looks like this (with some extra stuff added):</p>
<pre><code class="language-bash">#!/bin/bash

sanity_check() {
    if [[ -z &quot;${SSH_CONNECTION}&quot; ]]; then
        echo &quot;Who the hell are you?&quot; &gt;&amp;2
        exit 1
    fi

if [[ -z &quot;${SSH_ORIGINAL_COMMAND}&quot; ]]; then
        export SSH_ORIGINAL_COMMAND=&quot;info&quot;
fi
}

ask_for_info() {
    local userid=&quot;${1}&quot;

# make the request to the API to retrieve user info message
echo &quot;some info&quot;
}

ask_for_authorization() {
    local userid=&quot;${1}&quot;
    local appid=&quot;${2}&quot;

# make the request and return the HTTP status code here. 200 means authorized.
echo 200
}

authorize() {
    local userid=&quot;${1}&quot;
    local verb=&quot;${2}&quot;
    local appid=&quot;${3}&quot;
    local ret=1
    case &quot;${verb}&quot; in
        &quot;git-receive-pack&quot;|&quot;git-upload-pack&quot;)
            local code
            code=$(ask_for_authorization &quot;${userid}&quot; &quot;${appid}&quot;)
            [[ &quot;${code}&quot; == &quot;200&quot; ]] &amp;&amp; ret=0
            ;;
    esac
    return &quot;${ret}&quot;
}

final_abort() {
    echo &quot;What are you trying to achieve here?&quot; &gt;&amp;2
    exit 2
}
main() {
    sanity_check
    local userid=&quot;${1}&quot;
    local verb
    local repo
    local repo_dir
    verb=$(echo &quot;${SSH_ORIGINAL_COMMAND}&quot; | cut -d &#39; &#39; -f 1)
    repo=$(echo &quot;${SSH_ORIGINAL_COMMAND}&quot; | cut -d &#39; &#39; -f 2 | tr -d &quot;&#39;\&quot;&quot;)
    [[ &quot;${repo}&quot; == /* ]] &amp;&amp; repo=${repo:1}
    repo_dir=&quot;${REPOS_DIR}/${repo:0:6}/${repo:6:2}/${repo:8:2}/${repo}&quot;
    if [[ &quot;${verb}&quot; == &quot;info&quot; ]]; then
        ask_for_info &quot;${userid}&quot;
    elif authorize &quot;${userid}&quot; &quot;${verb}&quot; &quot;${repo}&quot;; then
        export CC_USER=&quot;${userid}&quot;
        export CC_NOTIFY_SCRIPT=&quot;${HOME}/.etilotig/send-push-event&quot;
        exec &quot;${verb}&quot; &quot;${repo_dir}&quot;
    else
        final_abort
    fi
}
. &quot;${HOME}&quot;/.etilotig/.etilotigrc
main &quot;${@}&quot;
</code></pre>
<p>With this in place, nearly everything was ready. Two tiny hooks on top of that to only allow users to push on the master branch, and to trigger a deployment on git push:</p>
<p><code>hooks/update</code></p>
<pre><code class="language-bash">#!/bin/bash

main() {
    local rev=&quot;${1}&quot;
    if [[ &quot;${rev}&quot; == refs/tags/* ]]; then
        exit 0
    fi
    if [[ &quot;${rev}&quot; != &quot;refs/heads/master&quot; ]]; then
        echo &quot;You tried to push to a custom branch.&quot;
        echo &quot;Only master is allowed.&quot;
        exit 1
    fi
}

main &quot;${@}&quot;
</code></pre>
<p><code>hooks/post-update</code></p>
<pre><code class="language-bash">#!/bin/bash

sanity_check() {
    local rev=&quot;${1}&quot;
    if [[ &quot;${rev}&quot; == refs/tags/* ]]; then
        exit 0
    fi
}

main () {
    local rev=&quot;${1}&quot;
    sanity_check &quot;${rev}&quot;
    local repo=$(basename $(pwd))
    local appId=${repo/.git/}
    local commitId=$(git rev-parse &quot;${rev}&quot;)
    &quot;${CC_NOTIFY_SCRIPT}&quot; &quot;${appId}&quot; &quot;${commitId}&quot; &quot;${CC_USER}&quot;
    echo &quot;[SUCCESS] The application has successfully been queued for redeploy.&quot;
}

main &quot;${@}&quot;
</code></pre>
<h3 id="conclusion">Conclusion</h3>
<p>That&#39;s it, we have our new git server manager up and running, which works pretty well.</p>
<p>The performance gain? We went from between 3 and more than 5 minutes to less than 1 second per action, while dropping the whole gitolite codebase and reducing the size of etilotig by 50%, with an average performance gain of 30k%.</p>
<p>gitolite has been very useful both in its utilisation and its codebase to better comprehend the whole authentication mechanism, so a great thanks to this awesome tool.</p>
<p>Now gitolite is dead, long live etilotig!</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Building an extensible HTTP client for GitHub in Java</title>
		<link>https://www.clever.cloud/blog/engineering/2015/03/24/simple-http-client-in-java/</link>
		
		<dc:creator><![CDATA[Marc-Antoine Perennou]]></dc:creator>
		<pubDate>Tue, 24 Mar 2015 16:32:00 +0000</pubDate>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">https://www2.cleverapps.io/wp/blog/technology/2015/03/24/simple-http-client-in-java/</guid>

					<description><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/http-client-java-1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="http client java 1" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2021/08/http-client-java-1.jpg 1400w, https://cdn.clever-cloud.com/uploads/2021/08/http-client-java-1-300x116.jpg 300w, https://cdn.clever-cloud.com/uploads/2021/08/http-client-java-1-1024x395.jpg 1024w, https://cdn.clever-cloud.com/uploads/2021/08/http-client-java-1-768x296.jpg 768w, https://cdn.clever-cloud.com/uploads/2021/08/http-client-java-1-1368x528.jpg 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p><p>At Clever Cloud, we use a lot of Java. A large part of our API is written using JEE (aka Java Enterprise Edition). Here is how we implemented the http client we use for <a href="https://www.clever.cloud/blog/features/2014/12/03/login-via-github/">our Github integration</a>.</p>
<span id="more-2796"></span>

<p>The standard HTTP implementation in JEE is <a href="https://jersey.java.net/">Jersey</a>, so that&#39;s what we&#39;ll use here.</p>
<h3 id="a-bit-of-background-first">A bit of background first</h3>
<p>Our API is designed in a &quot;micro-services&quot; way. There&#39;s a central part and various external components.</p>
<p>Here, we&#39;ll be dealing with the central part, which itself is internally designed in a sort-of &quot;micro-services&quot; way. JEE offers a powerful dependency injection mechanism called CDI, which we use to build a lot of small tools we can then use just as we need.</p>
<h3 id="serialization">Serialization</h3>
<p>When you&#39;re building APIs and clients, one of the problematics is about serialization. We made a tool to do just that which you&#39;ll see in the code as <code>MapperHelper</code>, namely <code>mh</code>. It&#39;s basically a wrapper around <a href="https://github.com/FasterXML/jackson">jackson</a>&#39;s <code>ObjectMapper</code>.</p>
<h3 id="lets-get-to-work">Let&#39;s get to work</h3>
<p>We&#39;ll be working on an internal tool called <code>GithubAPIHelper</code>. We&#39;ll not get through the whole of it, but you&#39;ll quickly get the concept.</p>
<p>First, some standard JEE boilerplate injecting required tools using CDI.</p>
<pre><code class="language-java">@Stateless
public class GithubAPIHelper {

   @Inject
   private MapperHelper mh;
   @Inject
   private LogsHelper lh;

   private final static String GITHUB_URL = &quot;https://api.github.com&quot;;
}
</code></pre>
<p>Now, we want to build an HTTP client using <code>jersey-client</code>, this is pretty straightforward. Btw, we create a method to make the client directly point at Github.</p>
<pre><code class="language-java">private Client getClient() {
   if (client == null) {
      client = ClientBuilder.newClient(new ClientConfig().property(ClientProperties.FOLLOW_REDIRECTS, true));
   }
   return client;
}

private WebTarget getTarget() {
   return getClient().target(GITHUB_URL);
}
</code></pre>
<p>What about authentication? Let&#39;s create a new method to get an authenticated request to Github:</p>
<pre><code class="language-java">private Invocation.Builder getBuilder(WebTarget target, String token) {
   return target.request().header(&quot;Authorization&quot;, &quot;token &quot; + token);
}
</code></pre>
<p>Ok, now that we have those basic pieces in place, we can start requesting for real.</p>
<p>Let&#39;s get the basic user profile, for starters</p>
<p>First, we create a basic data structure that we&#39;ll use to deserialize the payload from Github. I&#39;ll skip most of the available fields here as they&#39;re not needed.</p>
<pre><code class="language-java">public class GithubOwner implements Serializable {

   public int id;
   public String name;
   public String login;
   public String email;
   public String avatar_url;
}
</code></pre>
<p>Now, you should all be yelling at me about those public fields. Let me remember you that this data structure is only used for deserializing purpose, it won&#39;t ever be used for anything else, so what&#39;s the point in complicating things?</p>
<p>Now let&#39;s get back to business, we have a way to construct authenticated requests, and a model in which to store the data. So let&#39;s do it!</p>
<p>First, let&#39;s get to the right endpoint: <code>/user</code></p>
<pre><code class="language-java">   getTarget().path(&quot;/user&quot;);
</code></pre>
<p>Now, let&#39;s actually issue the request, and get a response</p>
<pre><code class="language-java">   Response r = getBuilder(getTarget().path(&quot;/user&quot;), token).get();
</code></pre>
<p>Let&#39;s deserialize the data from github</p>
<pre><code class="language-java">   GithubOwner owner = mh.readValue(r.readEntity(String.class), GithubOwner.class);
</code></pre>
<p>And here we are, with some integrity checks added:</p>
<pre><code class="language-java">   public GithubOwner getSelf(String token) {
      Response r = getBuilder(getTarget().path(&quot;/user&quot;), token).get();
      if (r.getStatus() &lt; 300) {
         try {
            GithubOwner owner = mh.readValue(r.readEntity(String.class), GithubOwner.class);
            return owner;
         } catch (IOException e) {
            lh.log(GithubAPIHelper.class.getName(), Level.SEVERE, null, e);
         }
      }
      return null;
   }
</code></pre>
<h3 id="dealing-with-pagination">Dealing with pagination</h3>
<p>Getting the user&#39;s profile was quite easy and straightforward, but everything isn&#39;t that smooth.</p>
<p>Let&#39;s say we now want all the repositories, instinctively, here is what we&#39;d do:</p>
<pre><code class="language-java">public class GithubRepository implements Serializable {

   public long id;
   public String name;
   public String description;
   public GithubOwner owner;
   @JsonProperty(value = &quot;private&quot;)
   public boolean isPrivate;
   public String ssh_url;
   public String git_url;
}
</code></pre>
<pre><code class="language-java">   private TypeSafeList&lt;GithubRepository&gt; getSelfRepositories(String token) {
      TypeSafeList&lt;GithubRepository&gt; repos = new TypeSafeArrayList&lt;&gt;();
      Response r = getBuilder(getTarget().path(&quot;/user/repos&quot;), token).get();
      if (r.getStatus() &lt; 300) {
         try {
            List&lt;GithubRepository&gt; ms = mh.readValue(r.readEntity(String.class), new TypeReference&lt;List&lt;GithubRepository&gt;&gt;() {
            });
            repos.addAll(new TypeSafeArrayList&lt;&gt;(ms));
         } catch (IOException e) {
            lh.log(GithubAPIHelper.class.getName(), Level.SEVERE, null, e);
         }
      }
      return repos;
   }
</code></pre>
<p>That will actually work, but you won&#39;t get all of them, only the first 20 or so. If you want all of them, you&#39;ll have to follow the pagination.</p>
<p>First, we want to get the link marked as <code>rel=next</code> in the <code>Link</code> http header.</p>
<pre><code class="language-java">   private String getNextLink(Response r) {
      String link = r.getHeaderString(&quot;Link&quot;);   /* &lt;http://foobar&gt;; rel=&quot;next&quot;, &lt;http://blah/&gt;; rel=last */
      if (link != null) {
         String[] links = link.split(&quot;,&quot;);
         for (String l : links) {               /* &lt;http://foobar&gt;; rel=&quot;next&quot; */
            if (l.contains(&quot;rel=\&quot;next\&quot;&quot;)) {
               String[] tmp1 = l.split(&quot;&lt;&quot;, 2);
               if (tmp1.length == 2) {
                  return tmp1[1].split(&quot;&gt;&quot;, 2)[0];  /* http://foobar */
               }
            }
         }
      }
      return null;
   }
</code></pre>
<p>Next, we want to request this url and get the next data to our initial request</p>
<pre><code class="language-java">   private Response getNextData(Response r, String token) {
      String link = getNextLink(r);
      if (link == null)
         return null;
      return getBuilder(getClient().target(link), token).get();
   }
</code></pre>
<p>Now let&#39;s put all the pieces together, addind a loop to retrieve all the data</p>
<pre><code class="language-java">   private TypeSafeList&lt;GithubRepository&gt; getSelfRepositories(String token) {
      TypeSafeList&lt;GithubRepository&gt; repos = new TypeSafeArrayList&lt;&gt;();
      Response r = getBuilder(getTarget().path(&quot;/user/repos&quot;), token).get();
      while (r != null) {
         if (r.getStatus() &lt; 300) {
            try {
               List&lt;GithubRepository&gt; ms = mh.readValue(r.readEntity(String.class), newhTypeReference&lt;List&lt;GithubRepository&gt;&gt;() {
               });
               repos.addAll(new TypeSafeArrayList&lt;&gt;(ms));
            } catch (IOException e) {
               lh.log(GithubAPIHelper.class.getName(), Level.SEVERE, null, e);
            }
         }
         r = getNextData(r, token);
      }
      return repos;
   }
</code></pre>
<p>And voila, you now have a working Github HTTP client. Once you got these, the other endpoints are really easy.</p>
]]></description>
										<content:encoded><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/http-client-java-1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="http client java 1" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2021/08/http-client-java-1.jpg 1400w, https://cdn.clever-cloud.com/uploads/2021/08/http-client-java-1-300x116.jpg 300w, https://cdn.clever-cloud.com/uploads/2021/08/http-client-java-1-1024x395.jpg 1024w, https://cdn.clever-cloud.com/uploads/2021/08/http-client-java-1-768x296.jpg 768w, https://cdn.clever-cloud.com/uploads/2021/08/http-client-java-1-1368x528.jpg 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p><p>At Clever Cloud, we use a lot of Java. A large part of our API is written using JEE (aka Java Enterprise Edition). Here is how we implemented the http client we use for <a href="https://www.clever.cloud/blog/features/2014/12/03/login-via-github/">our Github integration</a>.</p>
<span id="more-2796"></span>

<p>The standard HTTP implementation in JEE is <a href="https://jersey.java.net/">Jersey</a>, so that&#39;s what we&#39;ll use here.</p>
<h3 id="a-bit-of-background-first">A bit of background first</h3>
<p>Our API is designed in a &quot;micro-services&quot; way. There&#39;s a central part and various external components.</p>
<p>Here, we&#39;ll be dealing with the central part, which itself is internally designed in a sort-of &quot;micro-services&quot; way. JEE offers a powerful dependency injection mechanism called CDI, which we use to build a lot of small tools we can then use just as we need.</p>
<h3 id="serialization">Serialization</h3>
<p>When you&#39;re building APIs and clients, one of the problematics is about serialization. We made a tool to do just that which you&#39;ll see in the code as <code>MapperHelper</code>, namely <code>mh</code>. It&#39;s basically a wrapper around <a href="https://github.com/FasterXML/jackson">jackson</a>&#39;s <code>ObjectMapper</code>.</p>
<h3 id="lets-get-to-work">Let&#39;s get to work</h3>
<p>We&#39;ll be working on an internal tool called <code>GithubAPIHelper</code>. We&#39;ll not get through the whole of it, but you&#39;ll quickly get the concept.</p>
<p>First, some standard JEE boilerplate injecting required tools using CDI.</p>
<pre><code class="language-java">@Stateless
public class GithubAPIHelper {

   @Inject
   private MapperHelper mh;
   @Inject
   private LogsHelper lh;

   private final static String GITHUB_URL = &quot;https://api.github.com&quot;;
}
</code></pre>
<p>Now, we want to build an HTTP client using <code>jersey-client</code>, this is pretty straightforward. Btw, we create a method to make the client directly point at Github.</p>
<pre><code class="language-java">private Client getClient() {
   if (client == null) {
      client = ClientBuilder.newClient(new ClientConfig().property(ClientProperties.FOLLOW_REDIRECTS, true));
   }
   return client;
}

private WebTarget getTarget() {
   return getClient().target(GITHUB_URL);
}
</code></pre>
<p>What about authentication? Let&#39;s create a new method to get an authenticated request to Github:</p>
<pre><code class="language-java">private Invocation.Builder getBuilder(WebTarget target, String token) {
   return target.request().header(&quot;Authorization&quot;, &quot;token &quot; + token);
}
</code></pre>
<p>Ok, now that we have those basic pieces in place, we can start requesting for real.</p>
<p>Let&#39;s get the basic user profile, for starters</p>
<p>First, we create a basic data structure that we&#39;ll use to deserialize the payload from Github. I&#39;ll skip most of the available fields here as they&#39;re not needed.</p>
<pre><code class="language-java">public class GithubOwner implements Serializable {

   public int id;
   public String name;
   public String login;
   public String email;
   public String avatar_url;
}
</code></pre>
<p>Now, you should all be yelling at me about those public fields. Let me remember you that this data structure is only used for deserializing purpose, it won&#39;t ever be used for anything else, so what&#39;s the point in complicating things?</p>
<p>Now let&#39;s get back to business, we have a way to construct authenticated requests, and a model in which to store the data. So let&#39;s do it!</p>
<p>First, let&#39;s get to the right endpoint: <code>/user</code></p>
<pre><code class="language-java">   getTarget().path(&quot;/user&quot;);
</code></pre>
<p>Now, let&#39;s actually issue the request, and get a response</p>
<pre><code class="language-java">   Response r = getBuilder(getTarget().path(&quot;/user&quot;), token).get();
</code></pre>
<p>Let&#39;s deserialize the data from github</p>
<pre><code class="language-java">   GithubOwner owner = mh.readValue(r.readEntity(String.class), GithubOwner.class);
</code></pre>
<p>And here we are, with some integrity checks added:</p>
<pre><code class="language-java">   public GithubOwner getSelf(String token) {
      Response r = getBuilder(getTarget().path(&quot;/user&quot;), token).get();
      if (r.getStatus() &lt; 300) {
         try {
            GithubOwner owner = mh.readValue(r.readEntity(String.class), GithubOwner.class);
            return owner;
         } catch (IOException e) {
            lh.log(GithubAPIHelper.class.getName(), Level.SEVERE, null, e);
         }
      }
      return null;
   }
</code></pre>
<h3 id="dealing-with-pagination">Dealing with pagination</h3>
<p>Getting the user&#39;s profile was quite easy and straightforward, but everything isn&#39;t that smooth.</p>
<p>Let&#39;s say we now want all the repositories, instinctively, here is what we&#39;d do:</p>
<pre><code class="language-java">public class GithubRepository implements Serializable {

   public long id;
   public String name;
   public String description;
   public GithubOwner owner;
   @JsonProperty(value = &quot;private&quot;)
   public boolean isPrivate;
   public String ssh_url;
   public String git_url;
}
</code></pre>
<pre><code class="language-java">   private TypeSafeList&lt;GithubRepository&gt; getSelfRepositories(String token) {
      TypeSafeList&lt;GithubRepository&gt; repos = new TypeSafeArrayList&lt;&gt;();
      Response r = getBuilder(getTarget().path(&quot;/user/repos&quot;), token).get();
      if (r.getStatus() &lt; 300) {
         try {
            List&lt;GithubRepository&gt; ms = mh.readValue(r.readEntity(String.class), new TypeReference&lt;List&lt;GithubRepository&gt;&gt;() {
            });
            repos.addAll(new TypeSafeArrayList&lt;&gt;(ms));
         } catch (IOException e) {
            lh.log(GithubAPIHelper.class.getName(), Level.SEVERE, null, e);
         }
      }
      return repos;
   }
</code></pre>
<p>That will actually work, but you won&#39;t get all of them, only the first 20 or so. If you want all of them, you&#39;ll have to follow the pagination.</p>
<p>First, we want to get the link marked as <code>rel=next</code> in the <code>Link</code> http header.</p>
<pre><code class="language-java">   private String getNextLink(Response r) {
      String link = r.getHeaderString(&quot;Link&quot;);   /* &lt;http://foobar&gt;; rel=&quot;next&quot;, &lt;http://blah/&gt;; rel=last */
      if (link != null) {
         String[] links = link.split(&quot;,&quot;);
         for (String l : links) {               /* &lt;http://foobar&gt;; rel=&quot;next&quot; */
            if (l.contains(&quot;rel=\&quot;next\&quot;&quot;)) {
               String[] tmp1 = l.split(&quot;&lt;&quot;, 2);
               if (tmp1.length == 2) {
                  return tmp1[1].split(&quot;&gt;&quot;, 2)[0];  /* http://foobar */
               }
            }
         }
      }
      return null;
   }
</code></pre>
<p>Next, we want to request this url and get the next data to our initial request</p>
<pre><code class="language-java">   private Response getNextData(Response r, String token) {
      String link = getNextLink(r);
      if (link == null)
         return null;
      return getBuilder(getClient().target(link), token).get();
   }
</code></pre>
<p>Now let&#39;s put all the pieces together, addind a loop to retrieve all the data</p>
<pre><code class="language-java">   private TypeSafeList&lt;GithubRepository&gt; getSelfRepositories(String token) {
      TypeSafeList&lt;GithubRepository&gt; repos = new TypeSafeArrayList&lt;&gt;();
      Response r = getBuilder(getTarget().path(&quot;/user/repos&quot;), token).get();
      while (r != null) {
         if (r.getStatus() &lt; 300) {
            try {
               List&lt;GithubRepository&gt; ms = mh.readValue(r.readEntity(String.class), newhTypeReference&lt;List&lt;GithubRepository&gt;&gt;() {
               });
               repos.addAll(new TypeSafeArrayList&lt;&gt;(ms));
            } catch (IOException e) {
               lh.log(GithubAPIHelper.class.getName(), Level.SEVERE, null, e);
            }
         }
         r = getNextData(r, token);
      }
      return repos;
   }
</code></pre>
<p>And voila, you now have a working Github HTTP client. Once you got these, the other endpoints are really easy.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Github breaking changes that require your interaction</title>
		<link>https://www.clever.cloud/blog/features/2015/03/03/github-breaking-changes/</link>
		
		<dc:creator><![CDATA[Marc-Antoine Perennou]]></dc:creator>
		<pubDate>Tue, 03 Mar 2015 17:37:00 +0000</pubDate>
				<category><![CDATA[Features]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[oauth]]></category>
		<guid isPermaLink="false">https://www2.cleverapps.io/wp/blog/technology/2015/03/03/github-breaking-changes/</guid>

					<description><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/githubbreakingchangesbanner.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="githubbreakingchangesbanner" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2021/08/githubbreakingchangesbanner.png 1400w, https://cdn.clever-cloud.com/uploads/2021/08/githubbreakingchangesbanner-300x116.png 300w, https://cdn.clever-cloud.com/uploads/2021/08/githubbreakingchangesbanner-1024x395.png 1024w, https://cdn.clever-cloud.com/uploads/2021/08/githubbreakingchangesbanner-768x296.png 768w, https://cdn.clever-cloud.com/uploads/2021/08/githubbreakingchangesbanner-1368x528.png 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p><p>A couple of days ago, Github made breaking changes regarding the way other companies can interact with github organisations.</p>
<p>Usually, this wouldn&#39;t mean anything to you and you wouldn&#39;t need to do anything, but this time, Github requires you to explicitly approve Clever Cloud in order for your github applications to work properly.</p>
<span id="more-2858"></span>

<p>If you want to be able to create new applications from one of your github organisation&#39;s repositories, or if you want a <code>git push</code> to github to launch a deployment on Clever Cloud, you have two available solutions:</p>
<ul>
<li>The recommended one: Go to <a href="https://github.com" rel="noopener noreferrer" target="_blank">github</a>,
click on the settings (the little cog) button at the top right of your screen and then click on
<code>Applications</code> in the right column. If your github account is linked to your Clever Cloud one, you should see a line
saying <code>Clever Cloud API</code> with a <code>View</code> button next to it. Click this <code>View</code> button. At the bottom of your screen, you
can now grant Clever Cloud access to your organisations, or request an admin to do it.</li>
<li>The &quot;simpler&quot; but not recommended one: Go to github, click on the settings button at the top right of your screen,
click on an organisation to access its settings, then click <code>Third-party access</code> and then <code>Remove restrictions</code>. Note
that this solution can have several security issues.</li>
</ul>
<p>As a side note, github now requires more rights to be enabled to have access to an organisation repositories. You can make sure the rights associated to your account are up to date by logging out and then logging in again using github login.</p>
<p>Once you&#39;ve done this, everything should work back as expected.</p>
]]></description>
										<content:encoded><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/githubbreakingchangesbanner.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="githubbreakingchangesbanner" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2021/08/githubbreakingchangesbanner.png 1400w, https://cdn.clever-cloud.com/uploads/2021/08/githubbreakingchangesbanner-300x116.png 300w, https://cdn.clever-cloud.com/uploads/2021/08/githubbreakingchangesbanner-1024x395.png 1024w, https://cdn.clever-cloud.com/uploads/2021/08/githubbreakingchangesbanner-768x296.png 768w, https://cdn.clever-cloud.com/uploads/2021/08/githubbreakingchangesbanner-1368x528.png 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p><p>A couple of days ago, Github made breaking changes regarding the way other companies can interact with github organisations.</p>
<p>Usually, this wouldn&#39;t mean anything to you and you wouldn&#39;t need to do anything, but this time, Github requires you to explicitly approve Clever Cloud in order for your github applications to work properly.</p>
<span id="more-2858"></span>

<p>If you want to be able to create new applications from one of your github organisation&#39;s repositories, or if you want a <code>git push</code> to github to launch a deployment on Clever Cloud, you have two available solutions:</p>
<ul>
<li>The recommended one: Go to <a href="https://github.com" rel="noopener noreferrer" target="_blank">github</a>,
click on the settings (the little cog) button at the top right of your screen and then click on
<code>Applications</code> in the right column. If your github account is linked to your Clever Cloud one, you should see a line
saying <code>Clever Cloud API</code> with a <code>View</code> button next to it. Click this <code>View</code> button. At the bottom of your screen, you
can now grant Clever Cloud access to your organisations, or request an admin to do it.</li>
<li>The &quot;simpler&quot; but not recommended one: Go to github, click on the settings button at the top right of your screen,
click on an organisation to access its settings, then click <code>Third-party access</code> and then <code>Remove restrictions</code>. Note
that this solution can have several security issues.</li>
</ul>
<p>As a side note, github now requires more rights to be enabled to have access to an organisation repositories. You can make sure the rights associated to your account are up to date by logging out and then logging in again using github login.</p>
<p>Once you&#39;ve done this, everything should work back as expected.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>GitHub Login is Here!</title>
		<link>https://www.clever.cloud/blog/features/2014/12/03/login-via-github/</link>
		
		<dc:creator><![CDATA[Marc-Antoine Perennou]]></dc:creator>
		<pubDate>Wed, 03 Dec 2014 14:47:00 +0000</pubDate>
				<category><![CDATA[Features]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[release]]></category>
		<guid isPermaLink="false">https://www2.cleverapps.io/wp/blog/technology/2014/12/03/login-via-github/</guid>

					<description><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/github-integration-1.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="github integration 1" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2021/08/github-integration-1.png 1400w, https://cdn.clever-cloud.com/uploads/2021/08/github-integration-1-300x116.png 300w, https://cdn.clever-cloud.com/uploads/2021/08/github-integration-1-1024x395.png 1024w, https://cdn.clever-cloud.com/uploads/2021/08/github-integration-1-768x296.png 768w, https://cdn.clever-cloud.com/uploads/2021/08/github-integration-1-1368x528.png 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p>As you may have noticed, Clever Cloud added <a href="http://github.com">GitHub</a> integration for signup and login a few days ago. You can now create an account or link your existing one to GitHub, and then login in one click.

<span id="more-2854"></span>

Besides an easier authentication, there is a few other smooth features :
<ul>
 	<li>One-click import of ssh keys from GitHub</li>
 	<li>Application creation from a GitHub repository</li>
 	<li>Automatic deployments of several apps via a push to GitHub</li>
</ul>
If you want to enable automatic deployment, it's easy: in your application information tab, if you have created your application from a GitHub one, you will see a new field, a secret for your GitHub application's settings:
<ol>
 	<li>Grab this secret and go to the GitHub repository settings.</li>
 	<li>Click on "add a service" and select "Clever Cloud" from the list.</li>
 	<li>Paste the secret</li>
</ol>
That's it, every Clever Cloud application created from this repository will be automatically deployed whenever you push to GitHub.

Note that we also support private GitHub repositories, you only need to add the <a href="https://github.com/CleverCloudDeployer">CleverCloudDeployer</a> user to your repository. Note that read only access is sufficient.

If you want to link Github to your actual "email" account, head up to your profile settings, and click on "Link you GitHub Account".

Give it a try:

<center>
<a class="bt3-btn bt3-btn-success" href="https://api.clever-cloud.com/v2/sessions/login/">Join with GitHub!</a></center>]]></description>
										<content:encoded><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/github-integration-1.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="github integration 1" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2021/08/github-integration-1.png 1400w, https://cdn.clever-cloud.com/uploads/2021/08/github-integration-1-300x116.png 300w, https://cdn.clever-cloud.com/uploads/2021/08/github-integration-1-1024x395.png 1024w, https://cdn.clever-cloud.com/uploads/2021/08/github-integration-1-768x296.png 768w, https://cdn.clever-cloud.com/uploads/2021/08/github-integration-1-1368x528.png 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p>As you may have noticed, Clever Cloud added <a href="http://github.com">GitHub</a> integration for signup and login a few days ago. You can now create an account or link your existing one to GitHub, and then login in one click.

<span id="more-2854"></span>

Besides an easier authentication, there is a few other smooth features :
<ul>
 	<li>One-click import of ssh keys from GitHub</li>
 	<li>Application creation from a GitHub repository</li>
 	<li>Automatic deployments of several apps via a push to GitHub</li>
</ul>
If you want to enable automatic deployment, it's easy: in your application information tab, if you have created your application from a GitHub one, you will see a new field, a secret for your GitHub application's settings:
<ol>
 	<li>Grab this secret and go to the GitHub repository settings.</li>
 	<li>Click on "add a service" and select "Clever Cloud" from the list.</li>
 	<li>Paste the secret</li>
</ol>
That's it, every Clever Cloud application created from this repository will be automatically deployed whenever you push to GitHub.

Note that we also support private GitHub repositories, you only need to add the <a href="https://github.com/CleverCloudDeployer">CleverCloudDeployer</a> user to your repository. Note that read only access is sufficient.

If you want to link Github to your actual "email" account, head up to your profile settings, and click on "Link you GitHub Account".

Give it a try:

<center>
<a class="bt3-btn bt3-btn-success" href="https://api.clever-cloud.com/v2/sessions/login/">Join with GitHub!</a></center>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Is Clever Cloud Vulnerable to Shellshock?</title>
		<link>https://www.clever.cloud/blog/features/2014/09/25/is-clever-cloud-vulnerable-to-shellshock/</link>
		
		<dc:creator><![CDATA[Marc-Antoine Perennou]]></dc:creator>
		<pubDate>Thu, 25 Sep 2014 08:00:00 +0000</pubDate>
				<category><![CDATA[Features]]></category>
		<category><![CDATA[PaaS]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Update]]></category>
		<guid isPermaLink="false">https://www2.cleverapps.io/wp/blog/technology/2014/09/25/is-clever-cloud-vulnerable-to-shellshock/</guid>

					<description><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/shellshock-blog-1.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="shellshock blog 1" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2021/08/shellshock-blog-1.png 1400w, https://cdn.clever-cloud.com/uploads/2021/08/shellshock-blog-1-300x116.png 300w, https://cdn.clever-cloud.com/uploads/2021/08/shellshock-blog-1-1024x395.png 1024w, https://cdn.clever-cloud.com/uploads/2021/08/shellshock-blog-1-768x296.png 768w, https://cdn.clever-cloud.com/uploads/2021/08/shellshock-blog-1-1368x528.png 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p><p>Did you like [Heartbleed?]({{ site.basepath }}/features/2014/04/08/openssl-101g-update.html) Meet Shellshock — aka CVE-2014-6271 — a new bug discovered this week in the widely used Bash command line interpreter.</p>
<span id="more-2852"></span>

<h2 id="first-things-first">First things first</h2>
<blockquote>
<p>Are you safe at Clever Cloud?</p>
</blockquote>
<p>Yes. Yesterday afternoon (September, the 24th), a patch was released by the bash developpers to address this issue.</p>
<p>A member of our team, Kevin Decherf, then submitted an updated bash package with this patch to the distribution we use: <a href="http://exherbo.org">exherbo</a>.</p>
<p>The patch was reviewed by several members of the core exherbo team and finally validated by me, both as member of Clever Cloud and of the exherbo core team at around 5PM (CEST).</p>
<p>The update was then propagated inside our Cloud platform and all the critical virtual machines got bash updated today.</p>
<h2 id="what-about-you-localhost">What about you, &lt;localhost&gt;?</h2>
<p>You really should care about this new vulnerability.</p>
<p>It can compromise especially Apache web servers using CGI scripts with Bash invocation, making your system vulnerable to remote-code injection. 
OpenSSH and some DHCP clients are affected as well on machines that use Bash.</p>
]]></description>
										<content:encoded><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/shellshock-blog-1.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="shellshock blog 1" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2021/08/shellshock-blog-1.png 1400w, https://cdn.clever-cloud.com/uploads/2021/08/shellshock-blog-1-300x116.png 300w, https://cdn.clever-cloud.com/uploads/2021/08/shellshock-blog-1-1024x395.png 1024w, https://cdn.clever-cloud.com/uploads/2021/08/shellshock-blog-1-768x296.png 768w, https://cdn.clever-cloud.com/uploads/2021/08/shellshock-blog-1-1368x528.png 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p><p>Did you like [Heartbleed?]({{ site.basepath }}/features/2014/04/08/openssl-101g-update.html) Meet Shellshock — aka CVE-2014-6271 — a new bug discovered this week in the widely used Bash command line interpreter.</p>
<span id="more-2852"></span>

<h2 id="first-things-first">First things first</h2>
<blockquote>
<p>Are you safe at Clever Cloud?</p>
</blockquote>
<p>Yes. Yesterday afternoon (September, the 24th), a patch was released by the bash developpers to address this issue.</p>
<p>A member of our team, Kevin Decherf, then submitted an updated bash package with this patch to the distribution we use: <a href="http://exherbo.org">exherbo</a>.</p>
<p>The patch was reviewed by several members of the core exherbo team and finally validated by me, both as member of Clever Cloud and of the exherbo core team at around 5PM (CEST).</p>
<p>The update was then propagated inside our Cloud platform and all the critical virtual machines got bash updated today.</p>
<h2 id="what-about-you-localhost">What about you, &lt;localhost&gt;?</h2>
<p>You really should care about this new vulnerability.</p>
<p>It can compromise especially Apache web servers using CGI scripts with Bash invocation, making your system vulnerable to remote-code injection. 
OpenSSH and some DHCP clients are affected as well on machines that use Bash.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Wilcards on Domain Names</title>
		<link>https://www.clever.cloud/blog/features/2014/08/25/wildcards-on-domain-names/</link>
		
		<dc:creator><![CDATA[Marc-Antoine Perennou]]></dc:creator>
		<pubDate>Mon, 25 Aug 2014 00:00:00 +0000</pubDate>
				<category><![CDATA[Features]]></category>
		<category><![CDATA[domain names]]></category>
		<category><![CDATA[feature]]></category>
		<category><![CDATA[release]]></category>
		<guid isPermaLink="false">https://www2.cleverapps.io/wp/blog/technology/2014/08/25/wildcards-on-domain-names/</guid>

					<description><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/wildcards-banner-1.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="wildcards banner 1" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2021/08/wildcards-banner-1.png 1400w, https://cdn.clever-cloud.com/uploads/2021/08/wildcards-banner-1-300x116.png 300w, https://cdn.clever-cloud.com/uploads/2021/08/wildcards-banner-1-1024x395.png 1024w, https://cdn.clever-cloud.com/uploads/2021/08/wildcards-banner-1-768x296.png 768w, https://cdn.clever-cloud.com/uploads/2021/08/wildcards-banner-1-1368x528.png 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p>We've just released a new feature in the domain names management!

You can define for your domains a wildcard to match every sub-domain, meaning you don't need to define each sub-domain separately anymore!

<span id="more-2851"></span>

Now <code>*.example.com</code> will match every sub-domain on your app like <em>blog.example.com</em> or <em><a href="http://www.example.com">www.example.com</a></em>.

But for the raw domain <em>example.com</em>, you still need to add both <code>*.example.com</code> and <code>example.com</code> to your application's settings.

<center><img src="https://www2.cleverapps.io/app/uploads/2021/08/wildcard-domain-feature.jpg" /></center>For more information, this feature is documented here: <a href="https://www.clever.cloud/developers/doc/administrate/domain-names/">http://doc.clever-cloud.com/admin-console/custom-domain-names/</a>]]></description>
										<content:encoded><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/wildcards-banner-1.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="wildcards banner 1" decoding="async" loading="lazy" srcset="https://cdn.clever-cloud.com/uploads/2021/08/wildcards-banner-1.png 1400w, https://cdn.clever-cloud.com/uploads/2021/08/wildcards-banner-1-300x116.png 300w, https://cdn.clever-cloud.com/uploads/2021/08/wildcards-banner-1-1024x395.png 1024w, https://cdn.clever-cloud.com/uploads/2021/08/wildcards-banner-1-768x296.png 768w, https://cdn.clever-cloud.com/uploads/2021/08/wildcards-banner-1-1368x528.png 1368w" sizes="auto, (max-width: 1400px) 100vw, 1400px" /></p>We've just released a new feature in the domain names management!

You can define for your domains a wildcard to match every sub-domain, meaning you don't need to define each sub-domain separately anymore!

<span id="more-2851"></span>

Now <code>*.example.com</code> will match every sub-domain on your app like <em>blog.example.com</em> or <em><a href="http://www.example.com">www.example.com</a></em>.

But for the raw domain <em>example.com</em>, you still need to add both <code>*.example.com</code> and <code>example.com</code> to your application's settings.

<center><img src="https://www2.cleverapps.io/app/uploads/2021/08/wildcard-domain-feature.jpg" /></center>For more information, this feature is documented here: <a href="https://www.clever.cloud/developers/doc/administrate/domain-names/">http://doc.clever-cloud.com/admin-console/custom-domain-names/</a>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Knowing your system &#8211; Part 8 &#8211; On the road to upstream</title>
		<link>https://www.clever.cloud/blog/engineering/2013/02/05/knowing-your-system-part-8-on-the-road-to-upstream/</link>
		
		<dc:creator><![CDATA[Marc-Antoine Perennou]]></dc:creator>
		<pubDate>Tue, 05 Feb 2013 00:00:00 +0000</pubDate>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Developers]]></category>
		<guid isPermaLink="false">https://www2.cleverapps.io/wp/blog/technology/2013/02/05/knowing-your-system-part-8-on-the-road-to-upstream/</guid>

					<description><![CDATA[How did I start contributing? When I started to really dig into my system to fully understand how it works, breaking everything to know of to fix it, I decided to do even worse and started using scm packages. Scm packages download the source code directly for the upstream development repository using git, subversion, mercurial [&#8230;]]]></description>
										<content:encoded><![CDATA[<h2 id="how-did-i-start-contributing">How did I start contributing?</h2>
<p>When I started to really dig into my system to fully understand how it works, breaking everything to know of to fix it, I decided to do even worse and started using <a href="http://en.wikipedia.org/wiki/Source_Control_Management">scm</a> packages.</p>
<p><span id="more-2791"></span></p>
<p>Scm packages download the source code directly for the upstream development repository using <a href="http://git-scm.com/">git</a>, <a href="http://subversion.tigris.org/">subversion</a>, <a href="http://mercurial.selenic.com/">mercurial</a> or whatever other <a href="http://en.wikipedia.org/wiki/Revision_control">vcs</a>.</p>
<p>Doing this I ended up with a more-that-bleeding-edge system, causing a lot of breakages when stuff went incompatible with recent versions of other. That&#39;s perfect, since that&#39;s exactly the state I wanted to reach. If I wanted to recover a functional system, the easy solution that I adopted when I did not have much spare time was to revert my last changes and get back to an earlier version of the guilty package, but this was not the goal of the operation. What I really started to do at this point was to patch the broken stuff to make it compatible with the newer version of the guilty stuff which broke everything. It was sometimes really trivial, sometimes way less. I mostly did this for <a href="http://www.gnome.org/">Gnome</a> projects. It&#39;s a really good experience since you have to dig in a lot of projects and documentation, making you know better how various parts of your system work internally. Once I had everything back working, I then submitted my patches to the developers of the projects upstream, so that it gets fixed for everyone.</p>
<p>Now that I have way less spare time, I no longer have such a bleeding edge system, or at least I have way less scm packages. Sometimes I still need to patch stuff though, so I still use the same procedure.</p>
<h2 id="my-workflow">My workflow</h2>
<p>My workflow for contributing to upstream is not much different to <a href="http://www.imagination-land.org/posts/2013-01-03-knowing-your-system---part-7---contributing-to-exherbo.html">the one I use for contributing to Exherbo</a>. I also use an autopatch mechanism which is slightly different. My hook for automatically patch software is available there: <a href="https://github.com/Keruspe/paludis-config/blob/exherbo/hooks/ebuild_prepare_pre/patches.bash">https://github.com/Keruspe/paludis-config/blob/exherbo/hooks/ebuild_prepare_pre/patches.bash</a>. If I remember correctly it was initially written by <a href="http://ciaranm.wordpress.com/">Ciaran McCreesh</a>, the <a href="http://paludis.exherbo.org/">paludis</a>&#39;s lead developer. When I want to patch something, I get a copy locally, I write and commit my patch, I generate a patch file and move it to <code>/etc/paludis/autopatch/&lt;category&gt;/&lt;package&gt;/</code> where &lt;category&gt; is for example &quot;x11-dri&quot; and &lt;package&gt; is &quot;mesa&quot;, according to exherbo&#39;s packages name. Each time I install a package, it applies all this patches before configuring and compiling the software. If it works, I submit it upstream, if not, I fix it and retry.</p>
<p>I highly recommend you to try contributing to open source projects, to fix or improve them, like adding new functionalities. The only risk is to learn a lot.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
