﻿<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text" xml:lang="en">Package Management</title>
  <link type="application/atom+xml" href="https://d.moonfire.us/tags/package-management/atom.xml" rel="self" />
  <link type="text/html" href="https://d.moonfire.us/tags/package-management/" rel="alternate" />
  <updated>2026-06-05T17:38:36Z</updated>
  <id>https://d.moonfire.us/tags/package-management/</id>
  <author>
    <name>D. Moonfire</name>
  </author>
  <rights>Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International</rights>
  <entry>
    <title>Package Management - Formats and Registries</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2023/11/30/package-management-formats/" />
    <updated>2023-11-30T06:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2023/11/30/package-management-formats/</id>
    <category term="development" scheme="https://d.moonfire.us/categories/" label="Development" />
    <category term="package-management" scheme="https://d.moonfire.us/tags/" label="Package Management" />
    <category term="bakfu" scheme="https://d.moonfire.us/tags/" label="Bakfu" />
    <summary type="html">Thoughts on setting up formats and layering registries for those formats on top of each other.
</summary>
    <content type="html">&lt;p&gt;Since my mind has been on it, I wanted to work out some of the ideas I had for formats in my packaging system. In this case, I'm going to focus on a single one, NuGet, because I have a fair amount of experience with this and it has some of the complexities that are throwing me.&lt;/p&gt;
&lt;h2&gt;Series&lt;/h2&gt;
&lt;p&gt;This is going to be a series of posts, but I have no idea of how fast I'll be writing them out. I want to work out my ideas, maybe have a few conversations, and then start to move to more technical concepts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/07/package-management-introduction/"&gt;2023-02-07 Package Management - Introduction&lt;/a&gt; - The beginning of a short series as I write down my ideas of an ideal package system with the future goal of writing a generic system called Bakfu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/08/package-management-versions/"&gt;2023-02-08 Package Management - Versions&lt;/a&gt; - A short discussion on packages and their versions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/12/package-management-identifiers/"&gt;2023-02-12 Package Management - Identifiers&lt;/a&gt; - A short discussion on how to identify packages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/13/package-management-dependencies/"&gt;2023-02-13 Package Management - Dependencies&lt;/a&gt; - A review of different styles of package dependencies, including across different ecosystems, and then an attempt to consolidate them into a single unified system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/09/20/package-management-identifiers-2/"&gt;2023-09-20 Package Management - Identifiers 2&lt;/a&gt; - Using URNs to identify packages and some re-thinking of concepts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/11/30/package-management-formats/"&gt;2023-11-30 Package Management - Formats and Registries&lt;/a&gt; - Thoughts on setting up formats and layering registries for those formats on top of each other.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Configuration Files&lt;/h2&gt;
&lt;p&gt;All of the configuration for the system will be in a series of JSON5 (or JSON or whatever formats are officially supported) that are merged together with any conflict producing an error message and stopping the systems.&lt;/p&gt;
&lt;p&gt;Assuming &lt;code&gt;$GITDIR&lt;/code&gt; is the top-level directory for a Git repository, then the configuration would be in &lt;code&gt;$GITDIR/.config/bakfu&lt;/code&gt;. All the files will be gathered together, but a &lt;code&gt;.gitignore&lt;/code&gt; could ignore &lt;code&gt;*.user.*&lt;/code&gt; which means authentication information could be stored locally but have a common configuration on top of that.&lt;/p&gt;
&lt;p&gt;In this case, the files all have the same schema which is a required component because it also identifies the version of the file.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json5"&gt;{
    &amp;quot;$schema&amp;quot;: &amp;quot;...&amp;quot;,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Any more details on how we look for configuration files will have to wait for another post.&lt;/p&gt;
&lt;h2&gt;What is a Format?&lt;/h2&gt;
&lt;p&gt;Right now, a &amp;ldquo;format&amp;rdquo; is a specific format of a package, such as NuGet package or a NPM one. Inspired by SGML catalogs and how I like to see things in Git repositories, a format looks roughly like this JSON5.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json5"&gt;{
    // In this file, the various components don't have to be URL encoded.
    &amp;quot;formats&amp;quot;: {
        &amp;quot;nuget&amp;quot;: {
            &amp;quot;defaults&amp;quot;: {
                &amp;quot;authority&amp;quot;: &amp;quot;nuget&amp;quot;,
            },
            &amp;quot;authorities&amp;quot;: {
                &amp;quot;nuget&amp;quot;: {},
            },
        },
    },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since we merge files, that means I could create project-specific authority for packages that aren't (and probably never will be) on the official NuGet server. For example, my personal Forgejo instance at &lt;a href="https://src.mfgames.com/mfgames-cil"&gt;https://src.mfgames.com/mfgames-cil&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json5"&gt;{
    // In this file, the various components don't have to be URL encoded.
    &amp;quot;formats&amp;quot;: {
        &amp;quot;nuget&amp;quot;: {
            &amp;quot;authorities&amp;quot;: {
                &amp;quot;src.mfgames.com/mfgames-cil&amp;quot;: {},
            },
        },
    },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Authorities&lt;/h2&gt;
&lt;p&gt;The authority itself is the complex part of the file because it needs to handle how to search for packages, how to download them, authorization needed, and how verification is done.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json5"&gt;// merged formats.nuget.authorities:
&amp;quot;nuget&amp;quot;: {
    // &amp;quot;enabled&amp;quot;: true, // Implied so it can be disabled
    &amp;quot;registries&amp;quot;: {
        &amp;quot;nuget.org&amp;quot;: {
            &amp;quot;protocol&amp;quot;: &amp;quot;nuget-v3&amp;quot;,
            &amp;quot;url&amp;quot;: &amp;quot;https://api.nuget.org/v3/index.json&amp;quot;,
        },
    ],
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another file could merge additional registries in, much like you can have a proxy feed in DevOps.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json5"&gt;// merged formats.nuget.authorities:
&amp;quot;nuget&amp;quot;: {
    &amp;quot;registries&amp;quot;: {
        &amp;quot;nuget.org&amp;quot;: {
            &amp;quot;protocol&amp;quot;: &amp;quot;nuget-v3&amp;quot;,
            &amp;quot;url&amp;quot;: &amp;quot;https://api.nuget.org/v3/index.json&amp;quot;,
        },
        &amp;quot;example&amp;quot;: {
            &amp;quot;protocol&amp;quot;: &amp;quot;nuget-v3&amp;quot;,
            &amp;quot;url&amp;quot;: &amp;quot;https://example.org/proxied-feed/v3/index.json&amp;quot;,
        },
    },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Controlling Order&lt;/h3&gt;
&lt;p&gt;In the &lt;code&gt;NuGet.config&lt;/code&gt; file, there is also the ability to clear out the list of registries and use only a single set of identified registries. In this case, it would be a combination of disabling the known ones, changing the search for other files (the later post), and using a set of ordering controls.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json5"&gt;// merged formats.nuget.authorities:
&amp;quot;nuget&amp;quot;: {
    &amp;quot;registries&amp;quot;: {
        &amp;quot;nuget.org&amp;quot;: {
            &amp;quot;protocol&amp;quot;: &amp;quot;nuget-v3&amp;quot;,
            &amp;quot;url&amp;quot;: &amp;quot;https://api.nuget.org/v3/index.json&amp;quot;,
            &amp;quot;enabled&amp;quot;: &amp;quot;false&amp;quot;,
            // Below implies &amp;quot;search&amp;quot;: { &amp;quot;after&amp;quot;: [&amp;quot;example&amp;quot;] } }
        },
        &amp;quot;example&amp;quot;: {
            &amp;quot;protocol&amp;quot;: &amp;quot;nuget-v3&amp;quot;,
            &amp;quot;url&amp;quot;: &amp;quot;https://example.org/proxied-feed/v3/index.json&amp;quot;,
            &amp;quot;search&amp;quot;: {
                &amp;quot;before&amp;quot;: [&amp;quot;nuget.org&amp;quot;],
            }
        },
    },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Additional Packages&lt;/h3&gt;
&lt;p&gt;In &lt;code&gt;NuGet.config&lt;/code&gt;, it is possible to &lt;a href="https://learn.microsoft.com/en-us/nuget/consume-packages/package-source-mapping"&gt;map a set of packages&lt;/a&gt; to a given URL, such as all &lt;code&gt;MfGames*&lt;/code&gt; can only be found at a specific server. In those cases, that should be treated as a separate authority with its own set of registries (that may be a duplicate if it is also a proxy feed).&lt;/p&gt;
&lt;p&gt;In the example below, &lt;code&gt;contoso&lt;/code&gt; would be treated as a separate authority than the &lt;code&gt;nuget&lt;/code&gt; default.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-xml"&gt;&amp;lt;!-- NuGet.config --&amp;gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;
&amp;lt;configuration&amp;gt;
  &amp;lt;packageSourceMapping&amp;gt;
    &amp;lt;packageSource key=&amp;quot;nuget.org&amp;quot;&amp;gt;
      &amp;lt;package pattern=&amp;quot;*&amp;quot; /&amp;gt;
    &amp;lt;/packageSource&amp;gt;
    &amp;lt;packageSource key=&amp;quot;contoso.com&amp;quot;&amp;gt;
      &amp;lt;package pattern=&amp;quot;Contoso.*&amp;quot; /&amp;gt;
      &amp;lt;package pattern=&amp;quot;NuGet.Common&amp;quot; /&amp;gt;
    &amp;lt;/packageSource&amp;gt;
  &amp;lt;/packageSourceMapping&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Protocol&lt;/h3&gt;
&lt;p&gt;The protocol determines how the registry is accessed. I could see a number of possibilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NuGet V3 protocol, obviously NuGet-centric&lt;/li&gt;
&lt;li&gt;NPM access&lt;/li&gt;
&lt;li&gt;Directory location&lt;/li&gt;
&lt;li&gt;gRPC proxy server&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since this library needs to be implemented across a number of platforms and libraries, I would expect that unknown protocols would be filtered out (maybe with a warning) and then the ones that can be accessed are used. If there are no valid ones, then the system should blow up.&lt;/p&gt;
&lt;p&gt;The protocol also determines what additional settings might be required such as authentication, file system layout, or the like. It would be obvious specific to that protocol, so it is thrown into a generic &amp;ldquo;settings&amp;rdquo; object to control those things.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json5"&gt;&amp;quot;local&amp;quot;: {
    &amp;quot;protocol&amp;quot;: &amp;quot;file-v1&amp;quot;,
    &amp;quot;url&amp;quot;: &amp;quot;file:///${env:HOME}/src/other/project&amp;quot;,
    &amp;quot;settings&amp;quot;: {
        // The layout for &amp;quot;bob&amp;quot; would be &amp;quot;b/bob&amp;quot;.
        &amp;quot;package&amp;quot;: &amp;quot;${PACKAGE_NAME:0-0}/${PACKAGE_NAME}/${PACKAGE_VERSION}&amp;quot;,
    },
},
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Search Controls&lt;/h2&gt;
&lt;p&gt;Another aspect if how to handle searching. NuGet will search all the sources at the same time and the first one that responds gets it. However, in some cases, one might want only certain ones to be searched and then stop if it isn't there (such as a full feed proxy verses a subset proxy feed).&lt;/p&gt;
&lt;p&gt;I would see this as controlled by two components, at the authority and for an individual repository.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json5"&gt;// merged formats
&amp;quot;nuget&amp;quot;: {
    &amp;quot;authorities&amp;quot;: {
        &amp;quot;nuget&amp;quot;: {
            &amp;quot;search&amp;quot;: {
                &amp;quot;concurrent&amp;quot;: true,
                &amp;quot;defaultOrder&amp;quot;: &amp;quot;Alphabetical&amp;quot;,
            },
            &amp;quot;registries&amp;quot;: {
                &amp;quot;nuget.org&amp;quot;: {
                    &amp;quot;protocol&amp;quot;: &amp;quot;nuget-v3&amp;quot;,
                    &amp;quot;url&amp;quot;: &amp;quot;https://api.nuget.org/v3/index.json&amp;quot;,
                    &amp;quot;search&amp;quot;: {
                        &amp;quot;notFound&amp;quot;: &amp;quot;Stop&amp;quot;,
                        &amp;quot;timeout&amp;quot;: {
                            &amp;quot;time&amp;quot;: &amp;quot;00:01:00&amp;quot;,
                            &amp;quot;action&amp;quot;: &amp;quot;Retry&amp;quot;,
                            &amp;quot;maximumRetries&amp;quot;: 3,
                        },
                    },
                },
                &amp;quot;example&amp;quot;: {
                    &amp;quot;protocol&amp;quot;: &amp;quot;nuget-v3&amp;quot;,
                    &amp;quot;url&amp;quot;: &amp;quot;https://example.org/proxied-feed/v3/index.json&amp;quot;,
                    &amp;quot;search&amp;quot;: {
                        &amp;quot;notFound&amp;quot;: &amp;quot;Continue&amp;quot;,
                    },
                },
            },
        },
    },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Well, that's my thoughts on authorities and how to search them for packages. One thing you might notice is that I &lt;em&gt;don't&lt;/em&gt; have offline packages in the above examples. I want to treat offline (cached) files as a first-class concepts in the packaging and so that requires its own discussion. Not to mention, the cache is for all formats, not just one.&lt;/p&gt;
&lt;p&gt;I also want to eventually introduce the ability to have services provide opinions on packages. This way, I could set up a service that translates CVE alerts into controls of the packages found or allow a project-specific settings that would hide packages that were incompatible with the current project. I just don't know how to call them.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Computer science cannot solve two things: cache invalidation, how to name things, and off-by-one errors.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  <entry>
    <title>Package Management - Identifiers 2</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2023/09/20/package-management-identifiers-2/" />
    <updated>2023-09-20T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2023/09/20/package-management-identifiers-2/</id>
    <category term="development" scheme="https://d.moonfire.us/categories/" label="Development" />
    <category term="package-management" scheme="https://d.moonfire.us/tags/" label="Package Management" />
    <category term="mfgames-nitride" scheme="https://d.moonfire.us/tags/" label="MfGames.Nitride" />
    <category term="bakfu" scheme="https://d.moonfire.us/tags/" label="Bakfu" />
    <summary type="html">Using URNs to identify packages and some re-thinking of concepts.
</summary>
    <content type="html">&lt;p&gt;It's been a many (seven) months since I started working on the ideas of a package management system. A lot's happened but something got me down the path again and I decided to look at it again. This isn't a straight journey where I write every single post ahead of time but instead its more of ramblings and thoughts.&lt;/p&gt;
&lt;p&gt;Or, in the words of one of my favorite puzzle games, &lt;em&gt;The Thirtieth Guest&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Feeling lonely?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Series&lt;/h2&gt;
&lt;p&gt;This is going to be a series of posts, but I have no idea of how fast I'll be writing them out. I want to work out my ideas, maybe have a few conversations, and then start to move to more technical concepts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/07/package-management-introduction/"&gt;2023-02-07 Package Management - Introduction&lt;/a&gt; - The beginning of a short series as I write down my ideas of an ideal package system with the future goal of writing a generic system called Bakfu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/08/package-management-versions/"&gt;2023-02-08 Package Management - Versions&lt;/a&gt; - A short discussion on packages and their versions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/12/package-management-identifiers/"&gt;2023-02-12 Package Management - Identifiers&lt;/a&gt; - A short discussion on how to identify packages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/13/package-management-dependencies/"&gt;2023-02-13 Package Management - Dependencies&lt;/a&gt; - A review of different styles of package dependencies, including across different ecosystems, and then an attempt to consolidate them into a single unified system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/09/20/package-management-identifiers-2/"&gt;2023-09-20 Package Management - Identifiers 2&lt;/a&gt; - Using URNs to identify packages and some re-thinking of concepts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/11/30/package-management-formats/"&gt;2023-11-30 Package Management - Formats and Registries&lt;/a&gt; - Thoughts on setting up formats and layering registries for those formats on top of each other.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Mistakes Were Made&lt;/h2&gt;
&lt;p&gt;While I was reading &lt;a href="/blog/2023/02/12/package-management-identifiers/"&gt;the first identifiers post&lt;/a&gt;, I realized I made a few mistakes. One was that I was using a URL instead of a &lt;a href="https://en.wikipedia.org/wiki/Uniform_Resource_Name"&gt;URN&lt;/a&gt; to identify a package:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In contrast, URNs were conceived as persistent, location-independent identifiers assigned within defined namespaces, typically by an authority responsible for the namespace, so that they are globally unique and persistent over long periods of time, even after the resource which they identify ceases to exist or becomes unavailable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When it comes to identifying a package, that is exactly what we want. A persistent identifier that doesn't point to a specific location. When we want Markdowny, an important part is that we don't want to mandate &lt;em&gt;where&lt;/em&gt; to get it, but enough to identify it.&lt;/p&gt;
&lt;h2&gt;Rehashing as URN Components&lt;/h2&gt;
&lt;p&gt;URNs always start with &lt;code&gt;urn:&lt;/code&gt; and a registered &amp;ldquo;code&amp;rdquo;. We're going to pretend &lt;code&gt;bakfu&lt;/code&gt; is the registered code, so that means all the package identifiers would be &lt;code&gt;urn:bakfu:&lt;/code&gt; then something.&lt;/p&gt;
&lt;p&gt;Likewise, I think it is important to know when something is a package identifier (say &lt;code&gt;pkg:&lt;/code&gt;) or a reference to a package which has ranges (&lt;code&gt;ref:&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;EDIT: After looking at my notes, I already figured out why I didn't need this so I removed it from the content below.&lt;/p&gt;
&lt;p&gt;From earlier posts, I decided on the package format being a component with well-known versions (npm, nuget, deno) and arbitrary ones (domain-based).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;urn:bakfu:npm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;urn:bakfu:minetest&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;urn:bakfu:authorintrusion.com/spell-check&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the later examples below, I'm going to cut off the &lt;code&gt;urn:bakfu:&lt;/code&gt; as noise so &lt;code&gt;npm&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Authority&lt;/h2&gt;
&lt;p&gt;I don't have a lot of problems or doubt with the components above. The next part, on the other hand is a bit more complicated and fluid. As I develop more, I think we should have separate package repositories/registeries instead of putting everything at npmjs.com or nuget.org. However, that leads into potential name and identifier conflicts.&lt;/p&gt;
&lt;p&gt;Using the example from my life, when I started Nitride, I made all the namespaces &amp;ldquo;Nitride&amp;rdquo; and was going to buy a developer SSL to push it up to nuget.org. However, by the time I got to a stable point, there was then a Nitride already there and that didn't work.&lt;/p&gt;
&lt;p&gt;(This is also one reason why I don't like identifiers that aren't namespaced.)&lt;/p&gt;
&lt;p&gt;At the same time, I want to keep these URNs relatively &amp;ldquo;simple&amp;rdquo; for the 99% cases. In those cases, that means I want to aim for something like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm:markdowny&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm:@mfgames-writing/format&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nuget:Humanizer&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But, if there is a non-default location, the URN needs to have some mechanism that identifies the &amp;ldquo;authority&amp;rdquo; of a package. This authority doesn't need to be a URL, just a unique key to distinguish between two packages with the same identifier.&lt;/p&gt;
&lt;p&gt;Originally I thought about something like &lt;code&gt;npm:///markdowny&lt;/code&gt; based on using &lt;code&gt;file:///&lt;/code&gt; to reference the local file system but allow a domain and directory to be used:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm://mfgames.com/markdown&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm://mfgames.com/@mfgames-writing/epub2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm://example.org/~user/@example-organization/example-package&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The problem with that is the last one. Where does the directory structure end, where does the package begin? If the entire URL is opaque, then it would be easy to leave as-is, but because this has to translate, there needs to be an unequivocal way of splitting them into an authority and a package identifier.&lt;/p&gt;
&lt;p&gt;URL encoding to the rescue.&lt;/p&gt;
&lt;p&gt;If we treat the optional directory structure (on the optional authority domain) as a single &amp;ldquo;unit&amp;rdquo;, then we can keep the slash to separate authority from the identifier but still keep the identifier in its most common format (NPM uses slashes):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm:markdowny&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm:///markdowny&lt;/code&gt; (same as above)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm://npmjs.com/@mfgames-writing/epub2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm://npmjs.com%2F~dmoonfire/@mfgames-writing/epub2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think this would work because we can have a rule that states that the component after the package type has either two slashes for an authority and the next slash ends that component. Everything after that is the full identifier.&lt;/p&gt;
&lt;h3&gt;Well-Known URLs&lt;/h3&gt;
&lt;p&gt;I'm fond of the &lt;a href="https://en.wikipedia.org/wiki/Well-known_URI"&gt;.well-known/&lt;/a&gt; infrastructure that has built up over the years. I could easily envision that this could translate into an actual URL to help identify the location of the packages if not known.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://npmjs.com/.well-known/bakfu/npm/npmjs.com%2F%7Edmoonfire/@mfgames-writing/epub2"&gt;https://npmjs.com/.well-known/bakfu/npm/npmjs.com%2F~dmoonfire/@mfgames-writing/epub2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The resulting JSON file would give common locations where to find it. So going to the @mfgames-writing/epub well-known URL would then give the URLs for the official servers or locations, such as npmjs.com, my local package repository, an IPFS address, or whatever makes sense.&lt;/p&gt;
&lt;p&gt;The reason it won't use query strings like &lt;a href="https://webfinger.net/"&gt;webfinger&lt;/a&gt; is because query strings don't play well with static sites and I use static sites pretty heavily.&lt;/p&gt;
&lt;h2&gt;Qualified Identifiers&lt;/h2&gt;
&lt;p&gt;I think the ideas from the original identifiers post for qualified identifiers still have merit, but without the &lt;code&gt;bakfu:&lt;/code&gt; prefix because it ends up just being noise. I think these should be limited and defined ahead of time since there is flexibility on the features.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;java:org.example.hyphenated_name&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm:markdowny?version=1.1.0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo:serde?version=1.0.152&amp;amp;feature[]=derive&amp;amp;feature[]=rc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo:serde?version=1.0.152&amp;amp;platform=x86_64-unknown-linux-gnu&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Additional Versions&lt;/h3&gt;
&lt;p&gt;If the package version (as opposed to the content version) is needed, then &lt;code&gt;&amp;amp;package=1.0.0&lt;/code&gt; can be used. Likewise, if the Bakfu itself needs to be bumped, then &lt;code&gt;&amp;amp;bakfu=1.2.0&lt;/code&gt; can be used.&lt;/p&gt;
&lt;p&gt;I thought about making versions arbitrary, but I couldn't imagine a case where a package would have two different versions for two purposes. Those would be two separate packages in that case.&lt;/p&gt;
&lt;h3&gt;Overriding Packages&lt;/h3&gt;
&lt;p&gt;One of the reasons of this exercise is how to do a modification to a library that is already releases but the users learn after the fact that it breaks semantic versioning (SlimMessageBus). One constraint to this is that according to the &lt;a href="https://semver.org/#what-do-i-do-if-i-accidentally-release-a-backward-incompatible-change-as-a-minor-version"&gt;specification&lt;/a&gt;, the version of the content cannot change once published.&lt;/p&gt;
&lt;p&gt;That is why the package has its own version, to indicate that the package metadata such as the dependencies and requirements, can change independently of the contents. In most cases, &lt;code&gt;package=1.0.0&lt;/code&gt; but a proxy service could add in the modified dependency and call it &lt;code&gt;package=1.0.1-service&lt;/code&gt; which would then cause the packaging system to prefer the highest version of the package with the same version.&lt;/p&gt;
&lt;p&gt;There is some gaps because if we had a Bakfu-aware packaging system, someone could create a package and then keep bumping the package version higher to override anyone's overrides but I think this is a case where an upstream package modification should be blocked if there is an override given. At least until that new version can be reviewed and accepted.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The main reason to have these package identifiers is just to distinguish a package uniquely across the entire ecosystem. I strongly believe there needs to be a decoupling of the location verses identifier because of the other goals in this project: moving from one host to another, caching packages, being able to provide a curated list, blocking malicious packages, and to add after-the-fact changes.&lt;/p&gt;
&lt;p&gt;Overall, I think this fits my need for something that is roughly ascetic (&lt;code&gt;urn:bakfu:npm:markdowny?version=1.0.1&lt;/code&gt;), has a most-common use of something simple and readable (&lt;code&gt;urn:bakfu:npm:markdowny&lt;/code&gt;), but still allows distributed packages and cases where there are name collisions (&lt;code&gt;urn:bakfu:nuget://mfgames.com/Nitride&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;It also can be reduced to a common form based on context such as removing the &lt;code&gt;urn:bakfu:&lt;/code&gt; which makes the simplest version &lt;code&gt;npm:markdowny&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Also, it shouldn't be hard to create a normalized rule to turn it into a proper C# or Rust structure for doing the next steps.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Package Management - Dependencies</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2023/02/13/package-management-dependencies/" />
    <updated>2023-02-13T06:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2023/02/13/package-management-dependencies/</id>
    <category term="development" scheme="https://d.moonfire.us/categories/" label="Development" />
    <category term="package-management" scheme="https://d.moonfire.us/tags/" label="Package Management" />
    <category term="mfgames-nitride" scheme="https://d.moonfire.us/tags/" label="MfGames.Nitride" />
    <category term="bakfu" scheme="https://d.moonfire.us/tags/" label="Bakfu" />
    <summary type="html">A review of different styles of package dependencies, including across different ecosystems, and then an attempt to consolidate them into a single unified system.
</summary>
    <content type="html">&lt;p&gt;While packages can be self-contained, usually they have dependencies with other packages or even frameworks to avoid duplicating code. Without dependencies, packages would be forced to contain common logic that other packages share, and that code may become stale or not updated as frequently introducing potential bugs.&lt;/p&gt;
&lt;h2&gt;Series&lt;/h2&gt;
&lt;p&gt;This is going to be a series of posts, but I have no idea of how fast I'll be writing them out. I want to work out my ideas, maybe have a few conversations, and then start to move to more technical concepts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/07/package-management-introduction/"&gt;2023-02-07 Package Management - Introduction&lt;/a&gt; - The beginning of a short series as I write down my ideas of an ideal package system with the future goal of writing a generic system called Bakfu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/08/package-management-versions/"&gt;2023-02-08 Package Management - Versions&lt;/a&gt; - A short discussion on packages and their versions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/12/package-management-identifiers/"&gt;2023-02-12 Package Management - Identifiers&lt;/a&gt; - A short discussion on how to identify packages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/13/package-management-dependencies/"&gt;2023-02-13 Package Management - Dependencies&lt;/a&gt; - A review of different styles of package dependencies, including across different ecosystems, and then an attempt to consolidate them into a single unified system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/09/20/package-management-identifiers-2/"&gt;2023-09-20 Package Management - Identifiers 2&lt;/a&gt; - Using URNs to identify packages and some re-thinking of concepts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/11/30/package-management-formats/"&gt;2023-11-30 Package Management - Formats and Registries&lt;/a&gt; - Thoughts on setting up formats and layering registries for those formats on top of each other.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Simple Dependencies&lt;/h2&gt;
&lt;p&gt;For most systems, dependencies are very simple: this package requires these packages in this range. When working with Bakfu, this is almost identical to the package identifier but without the &lt;code&gt;bakfu:version&lt;/code&gt; and instead a range of values that are acceptable.&lt;/p&gt;
&lt;p&gt;Using &lt;a href="https://src.mfgames.com/mfgames-cil/-/packages/nuget/mfgames.nitride/0.15.1"&gt;MfGames.Nitride?version=0.15.1&lt;/a&gt; as an example, here is a fragment of what that could look like:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;{
    // Basically this is &amp;quot;bakfu:nuget:MfGames.Nitride?framework=net6.0&amp;quot;
    type: &amp;quot;nuget&amp;quot;,
    id: &amp;quot;MfGames.Nitride&amp;quot;,
    attributes: {
        &amp;quot;framework&amp;quot;: &amp;quot;net6.0&amp;quot;,
    },
    content: {
        version: &amp;quot;0.15.1&amp;quot;,
        dependencies: [
            &amp;quot;bakfu:nuget:Autofac?framework=net6.0&amp;quot;: &amp;quot;[6.4.0, 7.0.0)&amp;quot;,
            &amp;quot;bakfu:nuget:FluentValidation?framework=netstandard2.1&amp;quot;: &amp;quot;[11.2.1, 12.0.0)&amp;quot;,
            &amp;quot;bakfu:nuget:MfGames.Gallium?framework=net6.0&amp;quot;: &amp;quot;[0.4.0, 0.5.0)&amp;quot;,
        ],
    },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Replacements and Substitutions&lt;/h2&gt;
&lt;p&gt;While the above works in most cases, there are situations when it doesn't. Probably the easiest one to explain in in Minetest with multiple mods that replace the built-in &lt;code&gt;beds&lt;/code&gt; module: &lt;a href="https://content.minetest.net/packages/TenPlus1/beds/"&gt;TenPlus1's&lt;/a&gt; and &lt;a href="https://content.minetest.net/packages/sorcerykid/beds/"&gt;SorceryKid's&lt;/a&gt;. In all three of the cases, they are installed as &lt;code&gt;beds&lt;/code&gt; which is used for the dependency, but they are distinguished enough for our package system despite the same name.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;bakfu:minetest:beds&lt;/li&gt;
&lt;li&gt;bakfu:minetest:TenPlus1/beds&lt;/li&gt;
&lt;li&gt;bakfu:minetest:sorcerykid/beds&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the C# world, I've encountered this with the BouncyCastle libraries. In specific, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/BouncyCastle"&gt;BouncyCastle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/Portable.BouncyCastle"&gt;Portable.BouncyCastle&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both of these libraries have a 1.8.9 version and both of them have exactly the same DLL once it is build, &lt;code&gt;BouncyCastle.dll&lt;/code&gt;. In the past, this has caused us a lot of problem because while the two versions are API compatible (they have the same application binary interface, or ABI), they also overlap each other and have different packaging systems (one is only for .NET Framework, portable is more universally usable and currently maintained).&lt;/p&gt;
&lt;p&gt;Likewise, if someone abandoned a package in a fit of anger, say the &lt;a href="https://www.theverge.com/2016/3/24/11300840/how-an-irate-developer-briefly-broke-javascript"&gt;leftpad drama in the JavaScript&lt;/a&gt;, a strict package identifier means a replacement cannot be find. The same thing happens if a project maintainer dies &lt;a href="https://d.moonfire.us/garden/exit-planning/"&gt;without planning for a successor&lt;/a&gt;, there is a schism in the community causing a soft- or even hard-fork, or even someone using a Git repository or local copy to add some customization they need. Regardless, there are reasonable reasons for having two packages that proclaim to be the same version.&lt;/p&gt;
&lt;p&gt;To handle this, packages should list the aliases of what they provide (including themselves if needed) and that is what dependent packages would use. Using the BouncyCastle for an example:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;// BouncyCastle
{
    content: {
        id: &amp;quot;BouncyCastle&amp;quot;,
        version: &amp;quot;1.8.9&amp;quot;,
        attributes: {
            &amp;quot;framework&amp;quot;: &amp;quot;net&amp;quot;,
        },
        provides: [ &amp;quot;bakfu:nuget:BouncyCastle?bakfu:version=1.8.9&amp;amp;framework=net&amp;quot; ],
    },
}

// Portable.BouncyCastle
{
    content: {
        id: &amp;quot;Portable.BouncyCastle&amp;quot;,
        version: &amp;quot;1.8.9&amp;quot;,
        attributes: {
            &amp;quot;framework&amp;quot;: &amp;quot;net40&amp;quot;,
        },
        provides: [
            &amp;quot;bakfu:nuget:Portable.BouncyCastle?bakfu:version=1.8.9&amp;amp;framework=net40&amp;quot;,
            &amp;quot;bakfu:nuget:BouncyCastle?bakfu:version=1.8.9&amp;amp;framework=net&amp;quot;,
        ],
    },
}

// A third package
{
    content: {
        id: &amp;quot;Something.Else&amp;quot;,
        version: &amp;quot;1.0.0&amp;quot;,
        requires: {
            &amp;quot;bakfu:nuget:BouncyCastle?framework=net&amp;quot;: &amp;quot;[1.8.9,2.0.0)&amp;quot;,
        },
        // A missing provides would just produce the identity package
        // in this case, it would imply:
        // provides: { &amp;quot;bakfu.nuget:Something.Else?bakfu:version=1.0.0&amp;quot; }
    },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above example, if a module doesn't have a &lt;code&gt;provides&lt;/code&gt; element, then we could assume that it is just the identity version. &amp;ldquo;Something.Else&amp;rdquo; version 1.0.0 becomes &lt;code&gt;bakfu.nuget:Something.Else?version=1.0.0&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Publish and Subscribe&lt;/h2&gt;
&lt;p&gt;The above example doesn't handle optional dependencies. For example, Minetest modules can check for the presence of other modules and then hook up to them. Atom (one of my favorite editors that was sadly killed) had the idea of services where a package could provide a service (that had a version) and other packages could &amp;ldquo;consume&amp;rdquo; them. Using a fragment of my own &lt;code&gt;spell-check&lt;/code&gt;, it looked like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json"&gt;// from spell-check
&amp;quot;consumedServices&amp;quot;: {
  &amp;quot;spell-check&amp;quot;: {
    &amp;quot;versions&amp;quot;: {
      &amp;quot;^1.0.0&amp;quot;: &amp;quot;consumeSpellCheckers&amp;quot;
    }
  }
},

// from spell-check-project
&amp;quot;providedServices&amp;quot;: {
  &amp;quot;spell-check&amp;quot;: {
    &amp;quot;versions&amp;quot;: {
      &amp;quot;1.0.0&amp;quot;: &amp;quot;provideSpellCheck&amp;quot;
    }
  }
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above case, the editor would call use the callback method for every package that &amp;ldquo;provided&amp;rdquo; a service which would return an opaque object, which would then be handed to &lt;code&gt;spell-check&lt;/code&gt; consumed callback (&lt;code&gt;consumeSpellCheckers&lt;/code&gt;) as an array. That allowed optional dependencies by publishing a service and then having other packages subscribe to them.&lt;/p&gt;
&lt;p&gt;Even if the publisher (&lt;code&gt;spell-check&lt;/code&gt; in the above example) would get every subscriber, then doesn't mean that the publisher then could call something back into every subscriber that would let you wire the two together to allow for a reverse- or even bi-directional flow of data.&lt;/p&gt;
&lt;p&gt;Since this also has system-specific elements, we use the same &lt;code&gt;attributes&lt;/code&gt; construct to give flexibility to extend outside of Bakfu.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;{
    content: {
        id: &amp;quot;spell-check&amp;quot;,
        version: &amp;quot;0.77.1&amp;quot;,
        publish: {
            &amp;quot;bakfu:atom-service:spell-check&amp;quot;: {
                accept: &amp;quot;[1.0.0,2.0.0)&amp;quot;,
                attributes: {
                    callback: &amp;quot;consumeSpellCheckers&amp;quot;,
                },
            },
        },
    },
}

{
    content: {
        id: &amp;quot;spell-check-project&amp;quot;,
        version: &amp;quot;0.7.2&amp;quot;,
        subscribe: [
            &amp;quot;bakfu:atom-service:spell-check&amp;quot;: {
                accept: &amp;quot;[1.0.0,2.0.0)&amp;quot;,
                attributes: {
                    callback: &amp;quot;provideSpellCheck&amp;quot;,
                },
            },
        ],
    },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;How the application handles those services isn't in the domain of Bakfu, just the gathering and providing the information that links the two. It would also be based on the application if there can be multiple conflicting publishers (can two packages both publish the same service and version?) or not.&lt;/p&gt;
&lt;h2&gt;Categorizing Dependencies&lt;/h2&gt;
&lt;p&gt;The last major topic to cover for this post is how to categorize dependencies. NPM and C# both have the concept of development and production dependencies. NPM is a little easier to work with:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;// package.json
{
    dependencies: {
        &amp;quot;package-1&amp;quot;: &amp;quot;1.2.3&amp;quot;,
    },
    devDependencies: {
        &amp;quot;package-2&amp;quot;: &amp;quot;4.5.6&amp;quot;,
    },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rust is more complicated because enabling a feature also changes the dependencies of the package. Many crates don't include serialization, but if you add the &lt;code&gt;serde&lt;/code&gt; feature, it would include &lt;code&gt;serde&lt;/code&gt; and any other requirements. In effect, this is an optional dependency but determined at build item.&lt;/p&gt;
&lt;p&gt;It also changes how we organize dependencies above by adding an extra layer inside the &lt;code&gt;requires&lt;/code&gt; element that provides an application-specific set of keys. In Rust, this may also include every feature as a separate element of dependencies.&lt;/p&gt;
&lt;p&gt;(I could have started with this, but I wanted to build the blocks and work out the ideas on a single dependency before getting into the more complex situations.)&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;{
    content: {
        id: &amp;quot;Something.Else&amp;quot;,
        version: &amp;quot;1.0.0&amp;quot;,
        requires: {
            production: {
                &amp;quot;bakfu:nuget:BouncyCastle?framework=net&amp;quot;: &amp;quot;[1.8.9,2.0.0)&amp;quot;,
            },
            development: {
                &amp;quot;bakfu:nuget:DoesNotValidateInput&amp;quot;: &amp;quot;[1.0.0,2.0.0)&amp;quot;,
            },
        },
    },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another reason to have this categorization is to allow us to identify what packages are vulnerable in an &lt;a href="https://overreacted.io/npm-audit-broken-by-design/"&gt;intelligent mannner&lt;/a&gt; instead of just assuming any and all vulnerabilities are important. In other words, if you trust your developers not to use a DDoSing regular expression in their code, you don't have to patch that code.&lt;/p&gt;
&lt;h2&gt;Expanding Dependency References&lt;/h2&gt;
&lt;p&gt;One of the areas I'm not sure about is now to describe dependences and provides. In the above examples, I'm using the URI format but my gut feeling is that it should be the more verbose form to allow for extensions.&lt;/p&gt;
&lt;p&gt;The previous example would then look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;{
    content: {
        id: &amp;quot;Something.Else&amp;quot;,
        version: &amp;quot;1.0.0&amp;quot;,
        requires: {
            production: [
                {
                    type: &amp;quot;nuget&amp;quot;,
                    id: &amp;quot;BouncyCastle&amp;quot;,
                    accept: &amp;quot;[1.8.9,2.0.0)&amp;quot;,
                    attributes: {
                        framework: &amp;quot;net&amp;quot;,
                    },
                },
            ],
            development: [
                {
                    type: &amp;quot;nuget&amp;quot;,
                    id: &amp;quot;DoesNotValidateInput&amp;quot;,
                    accept: &amp;quot;[1.0.0,2.0.0)&amp;quot;,
                },
            },
        },
    },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I'm just not entirely sure about which one is the &amp;ldquo;best&amp;rdquo; but I'm also trying to work out ideas for a complete system, so I will probably use the URI unless the expanded makes sense. Ultimately, I really won't know until I've gotten through all the analysis and ideas before I can say one way or the other.&lt;/p&gt;
&lt;p&gt;(Though, I do lean toward more strict schema which means that the expanded form will probably be the final one.)&lt;/p&gt;
&lt;p&gt;I'm also not sure if the Bakfu format really needs to have &lt;code&gt;bakfu:&lt;/code&gt; in front of identifiers. I mean, it is inside the &amp;ldquo;bakfu&amp;rdquo; file.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Package Management - Identifiers</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2023/02/12/package-management-identifiers/" />
    <updated>2023-02-12T06:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2023/02/12/package-management-identifiers/</id>
    <category term="development" scheme="https://d.moonfire.us/categories/" label="Development" />
    <category term="package-management" scheme="https://d.moonfire.us/tags/" label="Package Management" />
    <category term="mfgames-nitride" scheme="https://d.moonfire.us/tags/" label="MfGames.Nitride" />
    <category term="bakfu" scheme="https://d.moonfire.us/tags/" label="Bakfu" />
    <summary type="html">A short discussion on how to identify packages.
</summary>
    <content type="html">&lt;p&gt;The other really big topic when it comes to package is how to identify them. This is a lot more complicated because I view packages in a polyglot manner instead of a single foreign ecosystem.&lt;/p&gt;
&lt;h2&gt;Series&lt;/h2&gt;
&lt;p&gt;This is going to be a series of posts, but I have no idea of how fast I'll be writing them out. I want to work out my ideas, maybe have a few conversations, and then start to move to more technical concepts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/07/package-management-introduction/"&gt;2023-02-07 Package Management - Introduction&lt;/a&gt; - The beginning of a short series as I write down my ideas of an ideal package system with the future goal of writing a generic system called Bakfu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/08/package-management-versions/"&gt;2023-02-08 Package Management - Versions&lt;/a&gt; - A short discussion on packages and their versions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/12/package-management-identifiers/"&gt;2023-02-12 Package Management - Identifiers&lt;/a&gt; - A short discussion on how to identify packages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/13/package-management-dependencies/"&gt;2023-02-13 Package Management - Dependencies&lt;/a&gt; - A review of different styles of package dependencies, including across different ecosystems, and then an attempt to consolidate them into a single unified system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/09/20/package-management-identifiers-2/"&gt;2023-09-20 Package Management - Identifiers 2&lt;/a&gt; - Using URNs to identify packages and some re-thinking of concepts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/11/30/package-management-formats/"&gt;2023-11-30 Package Management - Formats and Registries&lt;/a&gt; - Thoughts on setting up formats and layering registries for those formats on top of each other.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Previous Updates&lt;/h2&gt;
&lt;p&gt;While I got to thinking (this is a living series), I didn't like the upgrade format in the versions post of this series. In there, I suggested this for Bakfu:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;{
    content: {
        version: &amp;quot;1.10.0&amp;quot;,
        majorUpdate: &amp;quot;[1.10.0, 1.15.0)&amp;quot;,
        minorUpdate: &amp;quot;[1.10.0, 1.11.0)&amp;quot;,
    },
    package: {
        version: &amp;quot;2.0.0&amp;quot;,
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I think putting the update rules in their own category makes sense since they related to each other but also to handle adding other rules as needed in there. I thought about putting everything in a version, but then I would have &lt;code&gt;{version: { current: &amp;quot;1.2.3&amp;quot; }}&lt;/code&gt; which didn't feel right.&lt;/p&gt;
&lt;p&gt;We also should have the package format version.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;{
    bakfu: {
        version: &amp;quot;0.0.1&amp;quot;,
    },
    content: {
        version: &amp;quot;1.10.0&amp;quot;,
        update: {
            major: &amp;quot;[1.10.0, 1.15.0)&amp;quot;,
            minor: &amp;quot;[1.10.0, 1.11.0)&amp;quot;,
        },
    },
    package: {
        version: &amp;quot;2.0.0&amp;quot;,
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Identifier Schemas&lt;/h2&gt;
&lt;p&gt;A package identifier is one of those things that varies greatly between different languages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NPM: &lt;code&gt;markdowny&lt;/code&gt;, &lt;code&gt;@mfgames-writing/format&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;NuGet: &lt;code&gt;MfGames.Nitride&lt;/code&gt;, &lt;code&gt;System.Collections.Generic&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Minetest: &lt;code&gt;beds&lt;/code&gt;, &lt;code&gt;moreores&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Java: &lt;code&gt;com.mfgames.ruby&lt;/code&gt; (an old game of mine)&lt;/li&gt;
&lt;li&gt;Go: &lt;code&gt;github.com/callicoder/packer/numbers&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Cargo: &lt;code&gt;serde&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Atom: &lt;code&gt;spell-check&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That gives a pretty good overview of most languages that use packages. I don't think there are many other ways of referencing them. In addition to the ones above, I want to be able to allow anyone to create an arbitrary package ecosystem because I don't need to have a game using my calendar's packages (unless it wants to) but they are distinct.&lt;/p&gt;
&lt;h2&gt;Package Groups and Organizations&lt;/h2&gt;
&lt;p&gt;I will be up front, I don't like flat package systems such as Node and Cargo. They have a significant problem with name squatting (where someone &amp;ldquo;reserves&amp;rdquo; a package name that is ideal) and also because many of the packages are generic (Minetest's &lt;code&gt;beds&lt;/code&gt; or Node's &lt;code&gt;time&lt;/code&gt;) even if they are as capable.&lt;/p&gt;
&lt;p&gt;If you notice, almost all of my packages start with &lt;code&gt;mfgames&lt;/code&gt; or &lt;code&gt;MfGames&lt;/code&gt;. I do that to avoid conflicts with other packages. I thought I wouldn't for &lt;a href="/tags/mfgames-nitride/"&gt;Nitride&lt;/a&gt; but when I finally created the packages, someone had put one up on nuget.org and I promptly turned it back to &lt;code&gt;MfGames.Nitride&lt;/code&gt;. At this point, if someone is using &lt;code&gt;MfGames.&lt;/code&gt; in their packages, it's intentional (and probably malicious).&lt;/p&gt;
&lt;p&gt;Scoped packages are better, more so if there is a way of controlling who can use that scope. On nuget.org, you can reserve a prefix which is how they prevent someone from uploading a &lt;code&gt;Microsoft.HackYourComputer&lt;/code&gt; package. In theory, I could do the same with &lt;code&gt;MfGames&lt;/code&gt; but it requires some dependencies that I don't have lying around (cash).&lt;/p&gt;
&lt;p&gt;That said, I don't like NPM's &lt;code&gt;@organization&lt;/code&gt; because they &lt;em&gt;also&lt;/em&gt; use &lt;code&gt;@1.3.2&lt;/code&gt; for versions. So, then you have package and version identifiers as &lt;code&gt;@mfgames-writing/format@3.4.0&lt;/code&gt;. It isn't &amp;ldquo;pretty&amp;rdquo; and I am frequently driven by what I think looks good. As such, I'm inclined to avoid the &lt;code&gt;@&lt;/code&gt; whenever possible.&lt;/p&gt;
&lt;h2&gt;Polyglot Identifiers&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;pol·y·glot /ˈpälēˌɡlät/ -&amp;gt; adj. knowing or using several languages.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When working with code, not only do we use different packages, we use packages that require entirely different systems. Probably one of the most common one for me is the bane of my JavaScript and TypeScript development: &lt;code&gt;node-gyp&lt;/code&gt;. Node-gyp requires a C compiler and Python to run, but it is for Node packages. So, that means that if we really want to identify a package (and its dependencies, a later post), we need to be able to address all of those dependencies in the system addressing scheme.&lt;/p&gt;
&lt;h2&gt;Uniform Resource Identifiers (URIs)&lt;/h2&gt;
&lt;p&gt;Since I want to be able to identify packages by something that jumps languages, it seems like a perfect use of a &lt;a href="https://en.wikipedia.org/wiki/Uniform_Resource_Identifier"&gt;URI&lt;/a&gt;. In short, a URI looks like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;URI = scheme &amp;ldquo;:&amp;rdquo; [&amp;quot;//&amp;quot; authority] path [&amp;quot;?&amp;quot; query] [&amp;quot;#&amp;quot; fragment]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The most common one we see are URLs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fedran.com/flight-of-the-scions/"&gt;https://fedran.com/flight-of-the-scions/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the above example, &lt;code&gt;https&lt;/code&gt; is the scheme, &lt;code&gt;//fedran.com&lt;/code&gt; is the authority, and &lt;code&gt;flight-of-the-scions/&lt;/code&gt; is the path. If we take the same idea, we could create a pseudo version of package identifiers that use the same thing.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/markdowny"&gt;npm:markdowny&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/Humanizer"&gt;nuget:Humanizer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/charmbracelet/lipgloss"&gt;go:github.com/charmbracelet/lipgloss&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://content.minetest.net/packages/TenPlus1/ethereal/"&gt;minetest:ethereal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crates.io/crates/clap"&gt;cargo:clap&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(Side note, Humanizer is an awesome package for C# and everything Charm.sh is very pretty. Markdowny is my own tool for working with Markdown + YAML files, so I think it is fantastic.)&lt;/p&gt;
&lt;p&gt;This works for well-known package systems, but what about arbitrary ones? Say I create something for Author Intrusion, I could use &lt;code&gt;authorintrusion:spell-check&lt;/code&gt; but that would require registering a URI if I want to avoid conflict. A more efficient way (that I also will help with some future ideas) is to prefix them with &lt;code&gt;bakfu:&lt;/code&gt; instead and then allow domain or scoped registrations for non-well-known ecosystems.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bakfu:npm:markdown&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bakfu:go:github.com/charmbracelet/lipgloss&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bakfu:authorintrusion.com/spell-check&lt;/code&gt; (I really should do something about that website.)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Well-Known Systems and Aliases&lt;/h2&gt;
&lt;p&gt;Sadly, this does assume a centralized repository for the well-known (e.g., &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;go&lt;/code&gt;, &lt;code&gt;nuget&lt;/code&gt;) packages. It also leans into DNS instead of using other addressable schemas or pet names, I could also use &lt;code&gt;dotnet.microsoft.com&lt;/code&gt; for &lt;code&gt;nuget&lt;/code&gt; (since that is the general packaging system), &lt;code&gt;nodejs.org&lt;/code&gt;, and &lt;code&gt;go.dev&lt;/code&gt; for those languages.&lt;/p&gt;
&lt;p&gt;If I do go with the well-known, I would also have to establish a extension process that would allow communities to introduce new aliases or &amp;ldquo;register&amp;rdquo; their own to avoid conflict. While that isn't something I'd want to do, if this entire idea goes beyond me, it would be the first thing I would establish because I like to play well with others.&lt;/p&gt;
&lt;p&gt;I would also call it BEEP - Bakfu Emerging Extension Process so then I could have &lt;code&gt;BEEP-0000&lt;/code&gt; be the first one.&lt;/p&gt;
&lt;h2&gt;Qualified Identifiers&lt;/h2&gt;
&lt;p&gt;Using the URI, we can use URL-style query parameters to create a key/value pair for additional details about the package such as Cargo's features, .NET's frameworks, or whatever variants are important to include.&lt;/p&gt;
&lt;p&gt;For ones used by Bakfu, using a XML-style prefix would be more clear than either having a name collision (&lt;code&gt;version=&lt;/code&gt; could be common) or an arbitrary character prefix (&lt;code&gt;_&lt;/code&gt;). In these cases, &lt;code&gt;bakfu:version&lt;/code&gt; would be useful and allow for further extensions.&lt;/p&gt;
&lt;p&gt;For keys that need multiple, such as crate's features, the key would be suffixed by &lt;code&gt;[]&lt;/code&gt; to indicate an array (&amp;ldquo;Ruby style&amp;rdquo; is what I've heard this called).&lt;/p&gt;
&lt;p&gt;Rust has both platforms and featuers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bakfu:cargo:serde?bakfu:version=1.0.152&amp;amp;feature[]=derive&amp;amp;feature[]=rc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bakfu:cargo:serde?bakfu:version=1.0.152&amp;amp;platform=x86_64-unknown-linux-gnu&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;NuGet has frameworks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bakfu:nuget:Autofac?bakfu:version=6.5.0&amp;amp;framework=netstandard2.0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bakfu:nuget:Autofac?bakfu:version=6.5.0&amp;amp;framework=net6.0&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Given that, and the future discussion on dependencies, I think it would make sense to make it a query parameter instead of using the &lt;code&gt;#&lt;/code&gt; fragment. Also, some foreign ecosystems don't have versions (Minetest, at least one of the Python systems) which means even a version is optional.&lt;/p&gt;
&lt;h2&gt;Expanded Form&lt;/h2&gt;
&lt;p&gt;To simplify coding, the above URL could easily be broken down into a standard JSON structure for less condensed format with the &amp;ldquo;bakfu:&amp;rdquo; attributes pulled up a level.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;{
    // bakfu:cargo:serde?bakfu:version=1.0.152&amp;amp;feature[]=derive&amp;amp;feature[]=rc&amp;amp;platform=x86_64-unknown-linux-gnu

    type: &amp;quot;cargo&amp;quot;,
    id: &amp;quot;serde&amp;quot;,
    version: &amp;quot;1.0.152&amp;quot;,
    attributes: {
        &amp;quot;platform&amp;quot;: &amp;quot;x86_64-unknown-linux-gnu&amp;quot;,
        &amp;quot;features&amp;quot;: [&amp;quot;derive&amp;quot;, &amp;quot;rc&amp;quot;],
    },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the moment, I'm going to use both formats but I lean toward the more expanded form in actual files with the condensed URI form when trying to explain things. I'm sure I will bounce back and forth between something that feels &amp;ldquo;right&amp;rdquo;. You may also notice that I spell out most things because I don't like abbreviations while communicating concepts.&lt;/p&gt;
&lt;h2&gt;Distributed Packages&lt;/h2&gt;
&lt;p&gt;This is for a future topic, but I am planning on addressing distributed packages that don't encourage using only a single source for the data. So, the URI above only addresses the framework-level components that identify a distinct package irregardless if you find it on nuget.org, npmjs.com, gitlab.com, or even &lt;a href="https://src.mfgames.com/"&gt;src.mfgames.com&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Package Management - Versions</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2023/02/08/package-management-versions/" />
    <updated>2023-02-08T06:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2023/02/08/package-management-versions/</id>
    <category term="development" scheme="https://d.moonfire.us/categories/" label="Development" />
    <category term="package-management" scheme="https://d.moonfire.us/tags/" label="Package Management" />
    <category term="bakfu" scheme="https://d.moonfire.us/tags/" label="Bakfu" />
    <summary type="html">A short discussion on packages and their versions.
</summary>
    <content type="html">&lt;p&gt;The start of almost every package journey starts with versions. This is how one distinguishes between different copies and hopefully makes sense of when to get the latest version verses only updating a few or not updating at all.&lt;/p&gt;
&lt;h2&gt;Series&lt;/h2&gt;
&lt;p&gt;This is going to be a series of posts, but I have no idea of how fast I'll be writing them out. I want to work out my ideas, maybe have a few conversations, and then start to move to more technical concepts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/07/package-management-introduction/"&gt;2023-02-07 Package Management - Introduction&lt;/a&gt; - The beginning of a short series as I write down my ideas of an ideal package system with the future goal of writing a generic system called Bakfu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/08/package-management-versions/"&gt;2023-02-08 Package Management - Versions&lt;/a&gt; - A short discussion on packages and their versions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/12/package-management-identifiers/"&gt;2023-02-12 Package Management - Identifiers&lt;/a&gt; - A short discussion on how to identify packages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/13/package-management-dependencies/"&gt;2023-02-13 Package Management - Dependencies&lt;/a&gt; - A review of different styles of package dependencies, including across different ecosystems, and then an attempt to consolidate them into a single unified system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/09/20/package-management-identifiers-2/"&gt;2023-09-20 Package Management - Identifiers 2&lt;/a&gt; - Using URNs to identify packages and some re-thinking of concepts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/11/30/package-management-formats/"&gt;2023-11-30 Package Management - Formats and Registries&lt;/a&gt; - Thoughts on setting up formats and layering registries for those formats on top of each other.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The Semantic Dream&lt;/h2&gt;
&lt;p&gt;These days, almost every package system proclaims that they use &lt;a href="https://semver.org/"&gt;semantic versions&lt;/a&gt; and write the infrastructure as such. I love semantic versions with a passion, including putting them in my novels and stories. They are relatively clear and concise, and easy for me to understand: breaking-things.adding-things.fixing-things.&lt;/p&gt;
&lt;p&gt;The problem is, semantic versions are hard to manage when it comes to packages and dependencies, not to mention the business practices.&lt;/p&gt;
&lt;h2&gt;Romantic Versions&lt;/h2&gt;
&lt;p&gt;The biggest one are the ones who won't use it. One of the library I use during my day job is &lt;a href="https://korzh.com/"&gt;EasyQuery&lt;/a&gt; because they have a .NET and a JS library and give me a lot of flexibility in creating dynamic queries. They also are responsive to bug issues. What they don't do is follow semantic versions. They use romantic versions with every x.y version being a breaking change from the previous one. This applies to their code on NPM and NuGet.&lt;/p&gt;
&lt;p&gt;It is easy to manage, but you have to know that you can't go from 7.0.2 to 7.2.0 without major work, though semantic version says that it should have been a safe change.&lt;/p&gt;
&lt;p&gt;My day job product is also romantically versioned, so I deal with this on a quarterly basis.&lt;/p&gt;
&lt;h2&gt;Dependency Changes&lt;/h2&gt;
&lt;p&gt;Another example is &lt;code&gt;SlimMessageBus.Host&lt;/code&gt;. In version &lt;a href="https://www.fuget.org/packages/SlimMessageBus.Host/1.14.1"&gt;1.14.1&lt;/a&gt;, it requires &amp;ldquo;.netstandard2.0&amp;rdquo;. In &lt;a href="https://www.fuget.org/packages/SlimMessageBus.Host/1.15.0"&gt;1.15.0&lt;/a&gt;, it is &amp;ldquo;.netstandard2.1&amp;rdquo;. While this seems like safe change, it was a minor version bump that made it impossible for us to update because our product is still bound to &amp;ldquo;.netstandard2.0&amp;rdquo; until we can get off WebForms.&lt;/p&gt;
&lt;h2&gt;Version Ranges&lt;/h2&gt;
&lt;p&gt;Since it is important, there are also a number of ways of communicating version ranges. Node uses the &lt;code&gt;^&lt;/code&gt; for semantic versions and &lt;code&gt;~&lt;/code&gt; for &amp;ldquo;only patch updates&amp;rdquo; (basically what EasyQuery uses).&lt;/p&gt;
&lt;p&gt;NuGet uses a &lt;a href="https://learn.microsoft.com/en-us/nuget/concepts/package-versioning"&gt;different system&lt;/a&gt; such as &lt;code&gt;[1.0.0, 1.15.0)&lt;/code&gt; with the &lt;code&gt;[]&lt;/code&gt; meaning inclusive and &lt;code&gt;()&lt;/code&gt; meaning exclusive. This is my preferred system, mainly because it hearkens back to my computer science days and allows a mid-version break such as SlimMessageBus. In that regard, it is more flexible because &lt;code&gt;^&lt;/code&gt; and &lt;code&gt;~&lt;/code&gt; can translate directly into the verison range.&lt;/p&gt;
&lt;h2&gt;Being Explicit&lt;/h2&gt;
&lt;p&gt;I haven't gotten to dependencies yet, but the developer knows when something is safe update a package verses when it is not. EasyQuery knows that a patch is the breaking point, it would be better that they be able to communicate that as part of their metadata instead of requiring a customer support call. In effect, using the first two semantic version components (major and minor), EasyQuery 7.0.0 would be:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;{
    version: &amp;quot;7.0.0&amp;quot;,
    majorUpdate: &amp;quot;[7.0.0, 7.1.0)&amp;quot;,
    minorUpdate: &amp;quot;[7.0.0, 7.1.1)&amp;quot;, // The third number is their minor versions
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the other hand, SlimMessageBus would use (using an older version for illustrative purposes):&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;{
    version: &amp;quot;1.10.0&amp;quot;,
    majorUpdate: &amp;quot;[1.10.0, 1.15.0)&amp;quot;,
    minorUpdate: &amp;quot;[1.10.0, 1.11.0)&amp;quot;,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I'm assuming that anything more precise is a patch and is safe to update. I'm also think Bakfu should lean heavily on well-defined undefined values. So if &lt;code&gt;majorUpdate&lt;/code&gt;, then assume semantic version. If &lt;code&gt;minorUpdate&lt;/code&gt; is missing, then use &lt;code&gt;majorUpdate&lt;/code&gt; (which may be assumed).&lt;/p&gt;
&lt;h2&gt;Package Versions&lt;/h2&gt;
&lt;p&gt;The last bit is one that I've encountered a number of times while packaging books, but also while I was doing &lt;a href="https://manpages.debian.org/stretch/dpkg-dev/deb-version.5.en.html"&gt;Debian packages&lt;/a&gt;. The version of the package should be independent of the content. Using the above example, if SlimMessageBus realized they had made a breaking change, they should be able to update the 1.14.0 version of their package to indicate that 1.15.0 is a major breaking change.&lt;/p&gt;
&lt;p&gt;Today, their only choice would be to remove the 1.15.0 (and any later) version and create a 2.0.0 version. This can be a lot of work because most likely someone realized it after there were a number of updates already out in the field.&lt;/p&gt;
&lt;p&gt;Instead, if the package version was decoupled from the content version, then it would be possible to retroactively update critical information such as dependencies and safe upgrade ranges. Using SlimMessageBus again:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;{
    package: {
        version: &amp;quot;1.0.0&amp;quot;,
    },
    content: {
        version: &amp;quot;1.10.0&amp;quot;,
    },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After they realize the breaking change:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;{
    package: {
        version: &amp;quot;2.0.0&amp;quot;,
    },
    content: {
        version: &amp;quot;1.10.0&amp;quot;,
        majorUpdate: &amp;quot;[1.10.0, 1.15.0)&amp;quot;,
        minorUpdate: &amp;quot;[1.10.0, 1.11.0)&amp;quot;,
    },
}
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  <entry>
    <title>Package Management - Introduction</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2023/02/07/package-management-introduction/" />
    <updated>2023-02-07T06:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2023/02/07/package-management-introduction/</id>
    <category term="development" scheme="https://d.moonfire.us/categories/" label="Development" />
    <category term="package-management" scheme="https://d.moonfire.us/tags/" label="Package Management" />
    <category term="mfgames-culture" scheme="https://d.moonfire.us/tags/" label="MfGames.Culture" />
    <category term="author-intrusion" scheme="https://d.moonfire.us/tags/" label="Author Intrusion" />
    <category term="bakfu" scheme="https://d.moonfire.us/tags/" label="Bakfu" />
    <summary type="html">The beginning of a short series as I write down my ideas of an ideal package system with the future goal of writing a generic system called Bakfu.
</summary>
    <content type="html">&lt;p&gt;As I'm working through one project, I'm frequently planning the next. I noticed that a number of my future ideas, fantasies as you will, all have one thing in common: packages. It doesn't if it is a game idea or working on &lt;a href="/tags/mfgames-culture/"&gt;programming calendars&lt;/a&gt; or &lt;a href="/tags/author-intrusion/"&gt;Author Intrusion&lt;/a&gt;, they all need some form of package management.&lt;/p&gt;
&lt;p&gt;Given that and the rule of three, it makes sense to sit back and working that problem independent of the individual projects. Some people call this procrastinations. I like to call it composition. After a few months of rolling it around in my head, plus a bit of thoughts from Drew DeVault's &lt;a href="https://drewdevault.com/2021/09/27/Let-distros-do-their-job.html"&gt;various&lt;/a&gt; &lt;a href="https://drewdevault.com/2018/01/10/Learn-your-package-manager.html"&gt;posts&lt;/a&gt; on the topic, I figured I'd codify my ideas and see what I can do to create something I'm happy with in the future.&lt;/p&gt;
&lt;h2&gt;Series&lt;/h2&gt;
&lt;p&gt;This is going to be a series of posts, but I have no idea of how fast I'll be writing them out or if it will pan out, but this is a list of the related posts. I want to work out my ideas, maybe have a few conversations, and then start to move to more technical concepts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/07/package-management-introduction/"&gt;2023-02-07 Package Management - Introduction&lt;/a&gt; - The beginning of a short series as I write down my ideas of an ideal package system with the future goal of writing a generic system called Bakfu.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/08/package-management-versions/"&gt;2023-02-08 Package Management - Versions&lt;/a&gt; - A short discussion on packages and their versions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/12/package-management-identifiers/"&gt;2023-02-12 Package Management - Identifiers&lt;/a&gt; - A short discussion on how to identify packages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/02/13/package-management-dependencies/"&gt;2023-02-13 Package Management - Dependencies&lt;/a&gt; - A review of different styles of package dependencies, including across different ecosystems, and then an attempt to consolidate them into a single unified system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/09/20/package-management-identifiers-2/"&gt;2023-09-20 Package Management - Identifiers 2&lt;/a&gt; - Using URNs to identify packages and some re-thinking of concepts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2023/11/30/package-management-formats/"&gt;2023-11-30 Package Management - Formats and Registries&lt;/a&gt; - Thoughts on setting up formats and layering registries for those formats on top of each other.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Package Systems&lt;/h2&gt;
&lt;p&gt;Packages are awesome because they allow over developers provide components, they split apart logic into smaller chunks which make it easier to understand, and they can have different update paths instead of needing a single monolithic deployment. This also means, I'm more likely to be able to focus on a small part instead of having to &amp;ldquo;swap in&amp;rdquo; an entire project. That is one thing that has made Nitride a lot more enjoyable to work with.&lt;/p&gt;
&lt;p&gt;At their core idea, a package is just a &amp;ldquo;blob&amp;rdquo; of something along with metadata. For purposes of this series, I don't care what is in the blob. It could be C# code, a WASM binary, or Rust source. The thing I've gotten hung up is that we have a ton of different package systems (e.g., LISP modules, Python packages, NPM, Minetest, Debian packages) and each one was written for a specific use and has different rules. Some are nicer on the disk, others support signed code, and some have methods to avoid squatters. Every community wants to write their own for their specific uses, but to me it feels like we are reinventing the wheel so many times when we could be focusing on more fun things (unless packaging systems is your idea of fun, it is mine).&lt;/p&gt;
&lt;p&gt;(Yes, I'm aware that I want to write my own for my own specific purpose, but that's going to happen anyways. It's just a matter of what framework I write it in.)&lt;/p&gt;
&lt;h2&gt;Terminology&lt;/h2&gt;
&lt;p&gt;Since I'm thinking about doing a series of posts, here are some terms I plan on using:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Application - Whatever needs a package, be it a game, library, or utility.&lt;/li&gt;
&lt;li&gt;Bakfu - My hypothetical system for managing packages. This is the Lojban word for &amp;ldquo;package&amp;rdquo; and seems like a decent handle for what I'm working for.&lt;/li&gt;
&lt;li&gt;Foreign - Another packaging system.&lt;/li&gt;
&lt;li&gt;Package Ecosystem - All the servers, tools, and the packages themselves for a given type of packaging. This includes bakfu and foreign packaging ecosystems.&lt;/li&gt;
&lt;li&gt;Package Server - The servers used to query and distribute packages.&lt;/li&gt;
&lt;li&gt;Package - A specific type of package. This will have bakfu, application, or foreign as an adjective when necessary.&lt;/li&gt;
&lt;li&gt;Package Content - The &amp;ldquo;thing&amp;rdquo; being packaged. This can be a set of files, a word list, assets for a game, or even a foreign package. For purposes of these posts, this is a generic &amp;ldquo;blob&amp;rdquo; of data that is specific to an application.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Bakfu&lt;/h2&gt;
&lt;p&gt;I want something generic. More specifically, I want to find what I consider are the &amp;ldquo;best&amp;rdquo; parts of the various systems I've worked with, solve problems that I've experienced, and maybe come up with a set of libraries and utilities that let me implement a packaging ecosystem that only requires me to override the application-specific components while delegating the rest of the ecosystem to bakfu.&lt;/p&gt;
&lt;p&gt;I have no intent on this being a &amp;ldquo;standard&amp;rdquo; because everyone likes to reinvent the wheel. Everyone has their own idea of what is the &amp;ldquo;right&amp;rdquo; way of handling packages, even when there is a defacto standard already implemented.&lt;/p&gt;
&lt;p&gt;That isn't to say this is only going to be for me. Like most of my work, I'm hoping to create something generic enough that others can use it for any purpose and in the languages of their choice and still get some of the benefits I envision.&lt;/p&gt;
</content>
  </entry>
</feed>
