{"id":2985,"date":"2019-09-26T18:57:57","date_gmt":"2019-09-26T06:57:57","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=2985"},"modified":"2019-09-26T18:58:05","modified_gmt":"2019-09-26T06:58:05","slug":"duget-restore-update-and-whats-next","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/2985\/","title":{"rendered":"Duget &#8211; RESTORE, UPDATE and What&#8217;s Next ?"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">6<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span>\n<p>So far we&#8217;ve look at <a href=\"https:\/\/www.deltics.co.nz\/blog\/posts\/2979\">creating<\/a> and <a href=\"https:\/\/www.deltics.co.nz\/blog\/posts\/2983\">publishing<\/a> packages using <strong>duget<\/strong>.  This is of course an essential part of the process, but the real power comes when using those packages in your projects and ensuring that any dependencies you take also bring in their required dependencies and so on.<\/p>\n\n\n\n<p>This last post in this short series shows how that currently works in <strong>duget<\/strong>.<br><br><em><a href=\"https:\/\/www.deltics.co.nz\/blog\/posts\/2983\">As with the previous post<\/a><\/em><strong><em>, <\/em><\/strong><em>this was written before <a href=\"https:\/\/www.deltics.co.nz\/blog\/posts\/2915\">Liev arrived<\/a>. \ud83d\ude42<\/em><\/p>\n\n\n\n<!--more-->\n\n\n\n<p class=\"has-drop-cap\">Which brings us to the final file of interest: the project configuration file.  This identifies the packages that a particular project takes dependencies on.  Every project has potentially two such files that determine the dependencies for that project.  The first is the <em>path<\/em> configuration.  This is a <code>.duget<\/code> file in the same folder as the project.  The second is a <code>&lt;&lt;em&gt;project&lt;\/em&gt;&gt;.duget<\/code> file, sharing the same filename as the <strong>dpr<\/strong> but with the <code>.duget<\/code> extension.<\/p>\n\n\n\n<p>In complex projects with multiple <em><strong>dprs<\/strong><\/em> involved having common dependencies, this allows those dependencies to be specified just once at the path level, with only <em>project specific<\/em> dependencies then added if\/as needed in individual project files.  If no project configuration is provided then the path configuration applies and vice versa.<\/p>\n\n\n\n<p>Project and Path Configuration files provide facilities to identify dependencies that are specific to particular build configurations or platforms.  That is, your debug build configuration may take additional dependencies, e.g. on debugging tools\/frameworks, that your release builds do not.<\/p>\n\n\n\n<p class=\"has-text-color has-background has-very-light-gray-color has-vivid-red-background-color\"><strong>Project <\/strong><em><strong>Group<\/strong><\/em> configurations are specifically <strong><em>not<\/em><\/strong> supported.  This is because of the complication that a single project may conceivably exist in <em>multiple<\/em> project groups leading to the possibility that the same project could have <em>different dependencies depending on the project group context<\/em>.  This simply does not make sense for project dependencies. <\/p>\n\n\n\n<p>Build Config and Platform specific dependencies are already supported by <strong>duget<\/strong> but is the area perhaps most likely to change as part of the evolution of the configuration files so I won&#8217;t go into the current implementation.  Instead I&#8217;ll look at a simple scenario where a project simply takes dependencies that apply to all platforms and all build configurations:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-json\">{\n  references:[\n    &quot;&amp;..\\\\.duspec&quot;,\n    &quot;deltics.smoketest:2.0.2&quot;\n  ]\n}<\/code><\/pre>\n\n\n\n<p>This example is taken from the configuration for the tests project of another library that I am currently packaging.  This project implements the tests that are run to verify that a library may be packaged, only if it passes these tests.<\/p>\n\n\n\n<p>For this reason, and intended only for use in such scenarios, this configuration includes a dependency on a package <em>specification<\/em>.  This is denoted by the <code>&amp;<\/code> prefix on the reference, indicating that what follows is a path to a <code>.duspec<\/code> file, rather than a package.  This tells <strong>duget<\/strong> that this project (the test project) <em>directly<\/em> references the source for that package, as identified in the <em>package specification<\/em>.<\/p>\n\n\n\n<p>The second dependency is more straightforward.  Since the tests project uses <strong>Smoketest 2.0<\/strong> to implement the tests, it takes a dependency on that required package.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The RESTORE Command<\/h2>\n\n\n\n<p class=\"has-drop-cap\">To make sure that dependencies are available to a project for compilation, you simply use the <strong>restore<\/strong> command.  Again, the simplest version of this command will look for all <code>.duget<\/code> files in the current folder:<\/p>\n\n\n\n<p><code>duget restore<\/code><\/p>\n\n\n\n<p class=\"has-background has-very-light-gray-background-color\">It actually looks for <strong><em>dpr<\/em><\/strong> files and <em>then<\/em> for <em>applicable<\/em> <strong>.duget<\/strong> files at the path and project configuration level to be applied to each <strong><em>dpr<\/em><\/strong>.<\/p>\n\n\n\n<p>For each project <strong>duget restore<\/strong> will &#8220;walk the dependency tree&#8221;, loading packages from the cache where possible, fetching them from feeds where needed and then repeating that process for any dependencies that those packages bring in.  It will also bring in any <em>package dependencies<\/em> identified in the package specification for any source references (just referencing the source itself isn&#8217;t enough).<\/p>\n\n\n\n<p>If any dependency cannot be satisfied from the cache or any feed then the restore process fails.<\/p>\n\n\n\n<p class=\"has-background has-luminous-vivid-amber-background-color\">The <strong>restore<\/strong> command will <strong>not<\/strong> attempt to <em>update<\/em> the version of any package to any more current version.  Whatever version is specified is the version that will be provided.  If multiple versions of a given package are referenced in the dependency tree for a given project then the latest <em>compatible<\/em> version will be used.  If multiple <em>incompatible<\/em> versions are referenced then the restore command fails.  \u201cCompatibility\u201d of versions is determined using <a href=\"https:\/\/semver.org\/\">Semantic Versioning<\/a> rules.<\/p>\n\n\n\n<p>Just having the required packages in the cache isn&#8217;t enough of course.  As well as that, the <strong>restore<\/strong> command will unpack the source files from each package into a specially created folder under the projects.  Each package is unpacked into a folder named for the package id and version of the package involved.  So for two projects in the same folder referencing the same dependency, they share the unpacked folder.  e.g. the unpacked folder for deltics.smoketest:2.0.2 would be:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><em>&lt;projectfolder&gt;<\/em>\n   \\__duget\n       \\deltics.smoketest-2.0.2<\/pre>\n\n\n\n<p>If  two separate projects in the same folder reference different versions <em>of the same package<\/em>, then both will be unpacked but each project will reference only it&#8217;s required version. e.g. for two projects referencing different versions of <strong>deltics.smoketest<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><em>&lt;projectfolder&gt;<\/em>\n   \\__duget\n       \\deltics.smoketest-2.0.1\n       \\deltics.smoketest-2.0.2<\/pre>\n\n\n\n<p>But the <strong>restore<\/strong> command doesn&#8217;t stop there.  It also updates the -I, -R and -U settings of any <strong><em>&lt;project&gt;<\/em>.cfg<\/strong> file it finds with the paths to the required package folders in the <code>__duget<\/code> folder, for that project.<\/p>\n\n\n\n<p>It also updates the search path in any <strong>dproj<\/strong> file.<\/p>\n\n\n\n<p>The search path added to either <strong>cfg<\/strong> or <strong>dproj<\/strong> files also includes the path to the source files for any source referenced package.  Source file references (those &amp; prefixed .duspec references) are <em>not<\/em> copied to the <strong>__duget<\/strong> folder but have their actual source locations added to the search path(s).<\/p>\n\n\n\n<p class=\"has-background has-light-green-cyan-background-color\">Any non-<strong>duget<\/strong> paths present in the <strong>cfg<\/strong> or <strong>dproj<\/strong> settings already are preserved as-is.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The UPDATE Command<\/h2>\n\n\n\n<p>The last command to mention for now is <strong>duget update<\/strong>.  Since the <strong>restore<\/strong> command does <em>not<\/em> update package versions, the <strong>update<\/strong> command takes care of this.  Separating the two is important as you would want a <strong>duget restore<\/strong> in a build process to reliably restore the same packages used for all previous builds and the same versions on the dev machines (unless and until someone commits a change to update those dependencies).<\/p>\n\n\n\n<p><strong>duget update<\/strong> is a mechanism to simplify that business of updating dependencies on dev machines.  You would never run <strong>update<\/strong> on a build machine.<\/p>\n\n\n\n<p><strong>duget update<\/strong> also provides an additional level of forgiveness in your dependency configurations.  If you don&#8217;t know the current version of a package that you wish to use, but you do know the package id, then you can add a reference to just that package id and <strong>duget update<\/strong> will identify the latest version for you.  <strong>restore<\/strong> requires that a version is identified (except for &amp; source references, obviously).<\/p>\n\n\n\n<p>Again, the simplest possible invocation of the <strong>update<\/strong> command is:<\/p>\n\n\n\n<p><code>duget update<\/code><\/p>\n\n\n\n<p>And as with other commands, if you only wish to update a specific project (or projects) then specific projects may be identified as arguments.  Similarly if you only wish to update the version of a specific package (or packages) then this can be specified in a <code>\u2014package<\/code> option, e.g.:<\/p>\n\n\n\n<p><code>duget update myproject \u2014package:some.package;other.package<\/code><\/p>\n\n\n\n<p>So if you&#8217;re starting a new test project and want to use the latest version of <strong>smoketest<\/strong> and\/or other packages but don&#8217;t know what the latest versions are, you could create a dependency file similar to:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-json\">{\n  references:[\n    &quot;deltics.smoketest&quot;,\n    \u201cfastmm\u201d\n  ]\n}<\/code><\/pre>\n\n\n\n<p>Run <strong>duget update<\/strong> over that, and watch as the dependencies are updated to the latest versions and your project automatically configured to use them!  You could also specify a version of course, and this may be useful if you specifically don\u2019t want the absolute latest but do want the latest <em>compatible<\/em> version of some earlier major version.<\/p>\n\n\n\n<p class=\"has-background has-luminous-vivid-amber-background-color\">The only problem arises if a version is specified that doesn&#8217;t exist and there are not any versions later than that one available, in which case you\u2019re left with an invalid version in the dependency file.  So if you don&#8217;t know, you&#8217;re better off leaving it out.<\/p>\n\n\n\n<p>By default <strong>duget update<\/strong> will only update to a later, compatible release version of a package.  If you are willing to accept pre-release packages or breaking changes then as long as you have a feed configured which provides such releases, you can force <strong>duget update<\/strong> to take these with the addition of options on the command line:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">duget update --acceptPreRelease\nduget update --acceptBreaking\nduget update --acceptPreRelease --acceptBreaking<\/pre>\n\n\n\n<p>Whatever your appetite for change when updating, make sure you include a <strong>duget restore<\/strong> in your automated builds and you are good to go!<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What Next<\/h2>\n\n\n\n<p>The <strong>duget<\/strong> system is being exercised extensively in my current efforts to package my own code (and itself) for consumption using it but I will soon be looking for beta testers.  If anyone would like to help with IDE tooling I&#8217;d be particularly interested to hear from you.<\/p>\n\n\n\n<p>I am also starting to look at extending the coverage of this tool to <strong>FPC<\/strong> and <strong>Elements<\/strong> compiler technologies.<\/p>\n\n\n\n<p>Developers using <strong>Elements<\/strong> for <em>Android\/Java<\/em> or <em>.net<\/em> projects of course have the vast wealth of packages served up by the existing package ecosystems for those platforms, but <strong>Elements<\/strong> also supports native code development and a package management solution could have a place there.<\/p>\n\n\n\n<p>If you&#8217;re interested to get involved either as a tester or even as a contributor, let me know in the comments.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">6<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> Wrapping up this short series on duget, discussing RESTORE and UPDATE, arguably most important and useful commands in the duget repertoire.<\/p>\n","protected":false},"author":2,"featured_media":2981,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"Duget - RESTORE, UPDATE and What's Next ?  A look at consuming packages using the duget package manager.","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":[]},"categories":[324,323,4,321,346],"tags":[292,344,345],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/duget-warriors.png?fit=929%2C256&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-M9","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":2979,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2979\/","url_meta":{"origin":2985,"position":0},"title":"Duget Package Manager for Delphi","date":"24 Sep 2019","format":false,"excerpt":"An overview of the the duget package manager, outlining the current state of this project and the first in a quick-fire series to explore the key features.","rel":"","context":"In &quot;automation&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/duget-warriors.png?fit=929%2C256&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2983,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2983\/","url_meta":{"origin":2985,"position":1},"title":"Duget &#8211; PUSH-ing Packages","date":"25 Sep 2019","format":false,"excerpt":"We now know a little more about this duget thing, and have seen how to create a package. But a package cannot be consumed 'in situ' - it must be made available via a feed. Which brings us to the PUSH command.NOTE: Don\u2019t worry, I have my priorities straight. This\u2026","rel":"","context":"In &quot;automation&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/duget-warriors.png?fit=929%2C256&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":3000,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/3000\/","url_meta":{"origin":2985,"position":2},"title":"VersionInfo and Semantic Versioning","date":"08 Oct 2019","format":false,"excerpt":"How to make Semantic Version make sense in a VERSIONINFO world without Semantic Versioning.","rel":"","context":"In &quot;automation&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/bart-simpson-generator-1.png?fit=1024%2C343&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2919,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2919\/","url_meta":{"origin":2985,"position":3},"title":"Azure DevOps &#8211; Now You Too Can Use My Template(s)","date":"14 Sep 2019","format":false,"excerpt":"Learn how you too can use my Delphi build template in your own Azure DevOps pipelines, and a sneak preview of something special coming soon...","rel":"","context":"In &quot;automation&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/github-512.png?fit=512%2C512&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2936,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2936\/","url_meta":{"origin":2985,"position":4},"title":"Azure DevOps &#8211; Iterative Insertion Fixed!","date":"19 Sep 2019","format":false,"excerpt":"I figured out the iterative insertion problem and my build pipeline is now TIGHT! Fixing it was super-easy in fact, barely an inconvenience.","rel":"","context":"In &quot;automation&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/pipelines-hero-code-1024x256.jpg?fit=1024%2C256&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2931,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2931\/","url_meta":{"origin":2985,"position":5},"title":"&#8216;Sorry, this script is too long&#8230;&#8217;","date":"18 Sep 2019","format":false,"excerpt":"An object lesson on the importance of defensive programming and providing helpful error messages to your users.","rel":"","context":"In &quot;Azure DevOps&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Mark_Twain_life_1900s.jpg?fit=883%2C331&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2985"}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=2985"}],"version-history":[{"count":6,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2985\/revisions"}],"predecessor-version":[{"id":2998,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2985\/revisions\/2998"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media\/2981"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=2985"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=2985"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=2985"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}