Announcement

Collapse
No announcement yet.

Creating deb packages from scratch

Collapse
This topic is closed.
X
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Creating deb packages from scratch

    Code can get very complicated very quickly. As a result, often the best 'example' code is the simple stuff before a whole system evolves around the concepts. The "unfinished" projects may be more educational (and sometimes more inspiring) than monstrous creations that usually... well... almost do what we'd hoped they would.

    Description of this post:
    • An experiment to attempt to build *.deb packages with lzma compression and a very slightly more intuitive directory setup.


    [I do think you'll like the editor function if nothing else. Try 'editor /etc/fstab --line 12' and notice that kate opens in a new window. When you close it it will not close any other files you may have open in kate.]

    Creates DEB folder, which will contain the control files. Needs TREE folder containing the tree to install.

    TODO. Very primitive initialization at this point, but could be made to parse RPM specs or --info output or get a stater 'template' from existing installed software or packages.

    Requires: bash, dpgk, and dpgk-deb.

    Code:
    Start with a directory named TREE like so
     TREE ( image of root / )
      +- etc (if used)
    	+- config or inits
      +- usr
    	+- whatever you have that goes here
     DEB ( this folder will be created, but with no control file )
    DEB will be linked temporarily in the binary TREE as DEBIAN during build. The reason for not simply putting it in there and working with it there is for a) visibility, and b) doing it this way keeps the tree separate from the DEBIAN files for operations such as getting the installed size, generating md5sums, etc.

    Load these subroutines in bash with the command 'source deb-builder.sub'.
    Code:
    # file: deb-builder.sub
    
    HERE=$PWD
    
    #################################################
    ## helper subfunctions
    
    # An editor function opens kate in a new instance
    # and accepts --line ### to go to specific line.
    editor()
    { 
    cat << _eof > ~/tmp-editor.sh
    #!/bin/sh
    nohup kate -n \$@ > /dev/null 2>&1 &
    exit 0
    _eof
    bash ~/tmp-editor.sh $@
    rm ~/tmp-editor.sh
    }
    
    _get_md5sums()
    {
     local list
     cd TREE 
     list=`find * -type f`
     for i in $list; do
     md5sum $i
     done
     cd $HERE
    } 
    
    _get_blksize() # file or dir name
    { 
     local sz=0; 
     let sz=`stat $1 | sed '/Size:/!d; s| Size: ||; s| .*||'`
    # echo $sz
     let sz=$sz/512
     echo $sz
    }
    
    
    #################################################
    ## functions
    
    get_md5sums()
    {
     _get_md5sums > DEB/md5sums
    }
    
    
    init()
    {
     mkdir -p DEB
    echo "#!/bin/sh
    set -e
     " > DEB/postinst
    echo "#!/bin/sh
    set -e
     " > DEB/postrm
     chmod +x DEB/postinst
     chmod +x DEB/postrm
    }
    
    
    has_menus()
    {
    cat << _eof >> DEB/postinst
    # Automatically added by deb-builder
    if [ "\$1" = "configure" ] && [ -x "\`which update-menus 2>/dev/null\`" ]; then
    	update-menus
    fi
    # End automatically added section
    _eof
    
    cat << _eof >> DEB/postrm
    # Automatically added by deb-builder
    if [ -x "\`which update-menus 2>/dev/null\`" ]; then update-menus ; fi
    # End automatically added section
    _eof
    }
    
    
    edit_control()
    {
     editor DEB/control
    }
    
    
    get_tag() # tagname filedata
    {
     local tagname=$1
     local tagline=`echo "$2" | sed "/^$tagname/"'!'"d"`
     echo "$tagline" | sed "s|$tagname: *||"
    }
    
    
    get_pkgname()
    {
     local file="$(<DEB/control)"
     local pkg=`get_tag "Package" "$file"`
     local ver=`get_tag "Version" "$file"`
     local arch=`get_tag "Architecture" "$file"`
     echo $pkg"_"$ver"_"$arch
    }
    
    
    # just prints to stdout, does not write to the control file
    get_instsize()
    {
     echo "Installed-Size: $(blocksize TREE/*)"
    }
    
    get_blksize() # get size of all files under TREE
    {
     local total=0
     local next=0
     for i in `find TREE/*`; do
      let next=`_get_blksize $i`
      let total=$total+$next
     done
     echo "Installed-Size: $total"
    }
    
    build()
    { 
     cd $HERE # to make sure
     local pkgname=`get_pkgname`
     cd TREE
     rm -f DEBIAN
     ln -s ../DEB ./DEBIAN
     cd $HERE 
     dpkg -b TREE && mv TREE.deb $pkgname.deb || true
     rm TREE/DEBIAN
    }
    
    
    lzma_build()
    { 
     cd $HERE # to make sure
     local pkgname=`get_pkgname`
     cd TREE
    
     # don't recurse here or you can lose your files.. I KNOW this.
     rm -f DEBIAN # do this first to make sure
    
     # now we can make the symlink
     ln -s ../DEB ./DEBIAN
    
     cd $HERE 
     dpkg-deb -b -Z lzma TREE && mv TREE.deb $pkgname.deb || true
     rm TREE/DEBIAN
    }
    
    
    clean()
    {
    # rm -f `find * -name *~`
     rm -f TREE/DEBIAN
    }
    
    
    help()
    {
     echo "
     commands:
      init		- create DEB dir and init postinst/postrm scripts
      get_md5sums		- create MD5sum filename pairs
      has_menus		- append postinst and postrm for menus
      get_instsize	- (opt) get installed size before editing.
      edit_control	- (opt) edit the control file
      get_pkgname	- 	- show/verify name from defined fields in control file
      build	-	- build a debian *.deb package (recommended first time)
      lzma_build	-	- use lzma compression, smaller but takes longer
      clean	-	- clear out temps
    
     Note: runs in dir above TREE containing binary directory tree,
     optionally needs 'kate' to edit the control file. No templates yet.
     "
    }
    
    help
    As you can imagine, changing from this arrangement to a gui where buttons replace the commands would not be terrifically difficult.

    I prefer C/C++ anyway. :-)

    But this is an experiement you might find interesting, particularly as it creates deb packages that are quite a bit smaller, if that's an issue for you.

    The tighter compression may take longer to pack (done once) but they unpack very fast (done many times). As fast as tar.gz, believe it or not.

    xz and/or lzma is great stuff.

    Personal Explanation: I have dialup. I want to access my archives offline. The easiest way for me presently is a script-based installer/uninstaller similar to this one but with single-char commands, which is only one step away from becoming a GUI app.

    But most of my tools are in RPMs, many of which I created myself but which have directory structures that won't work with kubuntu. Then need to be modified to fit the debian directory trees.

    I'm porting these tools over to DEB using this setup (which is continually evolving).

    Once ported, things may start really getting interesting. :-)

    Especially for you internet-challenged folks like me. :-)

    But is any of this "experimental" stuff really useful?

    Copy the editor function above and paste it directly into a terminal, no other code is needed for this. Then type:
    Code:
    editor /etc/fstab --line 10
    Then do it again. Both instances remain open. Both instances are independent (i.e., you can close either one and the other will stay open).

    So is this stuff actually useful?

    You decide. :-)

    [Thanks for the tips from the kubuntu guys here that helped solve some of the issues involved here.]

    .

    #2
    Re: Creating deb packages from scratch

    Have you heard of the package equivs? I'd imagine this could help partially reduce the number of steps in your procedure.

    sriley@SRiley-T410:~$ apt-cache show equivs
    Package: equivs
    Priority: extra
    Section: universe/admin
    Installed-Size: 136
    Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
    Original-Maintainer: Peter Samuelson <peter@p12n.org>
    Architecture: all
    Version: 2.0.8
    Depends: perl, debhelper, dpkg-dev, make, fakeroot
    Filename: pool/universe/e/equivs/equivs_2.0.8_all.deb
    Size: 20342
    MD5sum: c1d63a4b5f8e9105689457f205b4ecd2
    SHA1: a6eb832775e92710b45421b93f5c7c6032aa5d1c
    SHA256: 36df7b4ef49f9bc5a1ca318dd3de58a172090ba242bd73a645 43a612b3e8fce9
    Description-en: Circumvent Debian package dependencies
    This package provides a tool to create trivial Debian packages.
    Typically these packages contain only dependency information, but they
    can also include normal installed files like other packages do.
    .
    One use for this is to create a metapackage: a package whose sole
    purpose is to declare dependencies and conflicts on other packages so
    that these will be automatically installed, upgraded, or removed.
    .
    Another use is to circumvent dependency checking: by letting dpkg
    think a particular package name and version is installed when it
    isn't, you can work around bugs in other packages' dependencies.
    (Please do still file such bugs, though.)
    Description-md5: eecadd6e89bb6f575d54f8f256a154aa
    Bugs: https://bugs.launchpad.net/ubuntu/+filebug
    Origin: Ubuntu

    Comment


      #3
      Re: Creating deb packages from scratch

      Both the debian packaging manual, as well as Ubuntu's are worth browsing so you don't reproduce what has already figured out, or has been scripted.

      Also a bit simpler how-to may be found, but digging one up can be time wasting, I can't find links to ones I have used
      I also believe that some sort of compression is done in kubuntu's packaging by default, what type I am unsure but it can be set in the rules file.

      there are already tons of built in toolsto help create and edit stuff in the debian folder.

      Comment


        #4
        Re: Creating deb packages from scratch

        rainbowsally wrote:

        So is this stuff actually useful?

        You decide.
        :-)

        ummmmmm thinking....ummmm thinking...

        ummmm YEAH!!! KEEEP IT GOING!!!

        woodhasnocluebutothersdosmoke
        sigpic
        Love Thy Neighbor Baby!

        Comment


          #5
          Re: Creating deb packages from scratch

          Ubuntu Packaging Guide: https://wiki.ubuntu.com/PackagingGuide/Complete

          Download Ubuntu Packaging Guide : https://launchpad.net/~ubuntu-packag.../ppa/+packages

          Code:
          :~$ apt-cache show ubuntu-packaging-guide
          Package: ubuntu-packaging-guide
          Status: install ok installed
          Priority: optional
          Section: doc
          Installed-Size: 4072
          Maintainer: Ubuntu Developers <*****>
          Architecture: all
          Version: 0.1-0~69~oneiric1
          Description: Ubuntu Packaging Guide
           The Ubuntu Packaging Guide is a set of articles that should help you to get
           involved with packaging and development of Ubuntu. It's not meant to replace
           other great documentation like the Debian New Maintainer's Guide or the
           Debian policy, but serve as a starting point with easy and simple to
           understand articles.
          Step by Step: https://wiki.ubuntu.com/PackagingGuide/Python
          - It is for the python scripts but the same method can be applied to the other sources.

          Gui

          - http://opendesktop.org/content/show....content=101776
          Debreate is utility to aid in building Debian packages (deb). The goal is to make developing for Debian based Linux distributions more appealing with an easy to use interface for packaging applications, artwork, media, etc.
          - http://qt-apps.org/content/show.php/KDebreate+(discontinued)?content=104257


          Packages

          packaging-dev
          This metapackage depends on common packages useful for the development of
          Debian-format packages, including patch management systems, build systems,
          packaging macros, helpful scripts for developers, and tools for building and
          testing packages.
          debhelper
          A collection of programs that can be used in a debian/rules file to
          automate common tasks related to building debian packages. Programs
          are included to install various files into your package, compress
          files, fix file permissions, integrate your package with the debian
          menu system, debconf, doc-base, etc. Most debian packages use debhelper
          as part of their build process.
          devscripts
          scripts to make the life of a Debian Package maintainer easier
          pkg-kde-tools
          various packaging tools and scripts for KDE Applications
          This package contains a variety of packaging tools and build scripts that may
          be very useful when packaging KDE applications. Even if you are a maintainer
          of a very small KDE application, this package should be worthwhile checking
          out.
          Have you tried ?

          - How to Ask a Question on the Internet and Get It Answered
          - How To Ask Questions The Smart Way

          Comment


            #6
            Re: Creating deb packages from scratch

            wait you mean i don't have to set up my debian folder and containing files manually. i have made a few .deb packages for mine (and others) programs. when getting set to be sure they would build correctly on the my PPA. after you have a ppa its all done by the ppa. you only upload source in an archive that contains the debian folder so it can compile and make the deb for you. so the question becomes what compression does the launchpad build service use because if we could get it to use lmza for all packages this would be of good for everyone.granted it would take a bit longer to compress, but that only happens once dl's and uncompress happens lots more(as stated above). Slow internet or not why download 5mb of a zip file when the same file lmza compressed is smaller lets say around 3mb smaller.something like this would help everyone and make transfers from the servers faster. i think if lanuchpad is not doing this then it needs to happen.
            Mark Your Solved Issues [SOLVED]
            (top of thread: thread tools)

            Comment


              #7
              Re: Creating deb packages from scratch

              Originally posted by SteveRiley
              Have you heard of the package equivs? I'd imagine this could help partially reduce the number of steps in your procedure.
              Thanks. I'll check it out.

              <snip>

              .
              Another use is to circumvent dependency checking: by letting dpkg
              think a particular package name and version is installed when it
              isn't, you can work around bugs in other packages' dependencies.
              (Please do still file such bugs, though.)
              Description-md5: eecadd6e89bb6f575d54f8f256a154aa
              Bugs: https://bugs.launchpad.net/ubuntu/+filebug
              Origin: Ubuntu
              I still don't really understand the tags in the control files yet. A Conflicts: or a Replaces: tag being used incorrectly might even do bad things.

              As I make my own packages, I'll learn the difference though, I suspect. ;-)

              Thanks for the tip about equivs.

              Comment


                #8
                Re: Creating deb packages from scratch

                Originally posted by woodsmoke
                rainbowsally wrote:

                So is this stuff actually useful?

                You decide.
                :-)

                ummmmmm thinking....ummmm thinking...

                ummmm YEAH!!! KEEEP IT GOING!!!

                woodhasnocluebutothersdosmoke
                The default is gzip for the control files, tar.gzip for the data (directory tree).

                dpkg doesn't have a way to change the compression type but dpkg-deb does.

                Woops. Wrong reply. :-) Sorry, I thought this was claydoh's. Must have hit the wrong {quote} button.

                No harm done... :-)

                Oh. And the final package is archived with 'ar' I think. The first 6 bytes are
                '<arch>' (including the pointy braces) in any case. And I think that's the binary id for ar files.

                So I get the same results different methods.

                I shall "keep it going", and thanks for the replies.

                Comment


                  #9
                  Re: Creating deb packages from scratch

                  Copied to file. (I'm stuck with windows for my dialup.) Some of that might already be on the DVD.

                  Thanks.

                  I'm aiming for a gui-based tool, eventually. The scripts mentioned here are "accessible" though (i.e., source code by definition), and if they aren't overly complicated (like rpmrebuild was... boy what a maze that is to follow), Im sure some of the ideas and tricks of the trade here will be helpful.


                  Originally posted by OneLine
                  Ubuntu Packaging Guide: https://wiki.ubuntu.com/PackagingGuide/Complete

                  Download Ubuntu Packaging Guide : https://launchpad.net/~ubuntu-packag.../ppa/+packages

                  Code:
                  :~$ apt-cache show ubuntu-packaging-guide
                  Package: ubuntu-packaging-guide
                  Status: install ok installed
                  Priority: optional
                  Section: doc
                  Installed-Size: 4072
                  Maintainer: Ubuntu Developers <*****>
                  Architecture: all
                  Version: 0.1-0~69~oneiric1
                  Description: Ubuntu Packaging Guide
                   The Ubuntu Packaging Guide is a set of articles that should help you to get
                   involved with packaging and development of Ubuntu. It's not meant to replace
                   other great documentation like the Debian New Maintainer's Guide or the
                   Debian policy, but serve as a starting point with easy and simple to
                   understand articles.
                  Step by Step: https://wiki.ubuntu.com/PackagingGuide/Python
                  - It is for the python scripts but the same method can be applied to the other sources.

                  Gui

                  - http://opendesktop.org/content/show....content=101776
                  Debreate is utility to aid in building Debian packages (deb). The goal is to make developing for Debian based Linux distributions more appealing with an easy to use interface for packaging applications, artwork, media, etc.
                  - http://qt-apps.org/content/show.php/KDebreate+(discontinued)?content=104257


                  Packages

                  packaging-dev
                  This metapackage depends on common packages useful for the development of
                  Debian-format packages, including patch management systems, build systems,
                  packaging macros, helpful scripts for developers, and tools for building and
                  testing packages.
                  debhelper
                  A collection of programs that can be used in a debian/rules file to
                  automate common tasks related to building debian packages. Programs
                  are included to install various files into your package, compress
                  files, fix file permissions, integrate your package with the debian
                  menu system, debconf, doc-base, etc. Most debian packages use debhelper
                  as part of their build process.
                  devscripts
                  scripts to make the life of a Debian Package maintainer easier
                  pkg-kde-tools
                  various packaging tools and scripts for KDE Applications
                  This package contains a variety of packaging tools and build scripts that may
                  be very useful when packaging KDE applications. Even if you are a maintainer
                  of a very small KDE application, this package should be worthwhile checking
                  out.

                  Comment


                    #10
                    Re: Creating deb packages from scratch

                    Originally posted by sithlord48
                    wait you mean i don't have to set up my debian folder and containing files manually. i have made a few .deb packages for mine (and others) programs. when getting set to be sure they would build correctly on the my PPA. after you have a ppa its all done by the ppa. you only upload source in an archive that contains the debian folder so it can compile and make the deb for you. so the question becomes what compression does the launchpad build service use because if we could get it to use lmza for all packages this would be of good for everyone.granted it would take a bit longer to compress, but that only happens once dl's and uncompress happens lots more(as stated above). Slow internet or not why download 5mb of a zip file when the same file lmza compressed is smaller lets say around 3mb smaller.something like this would help everyone and make transfers from the servers faster. i think if lanuchpad is not doing this then it needs to happen.
                    Probably only 2mb smaller (and uncompresses just as fast, though compression is slower).

                    Thanks for the comments!

                    I don't like the regular DEBIAN usr etc folder layout because it can't be used by anything else. If the DEBIAN folder is kept somewhere else the same directory tree can be used by 'make' (without any special parsing when creating the makefile) or RPM or whatever.

                    Good observations though. Thanks again.

                    Comment


                      #11
                      Re: Creating deb packages from scratch


                      Kubuntu's KDE packages, from the scripts in pkg-kde-tools, already use lzma compression, and have for quite some time now. I am not sure if Ubuntu does, I would be surprised if not as the single-cd image format has caused us all to do whatever we can to save space over the years. Again, there are flags that can be used in the debian/rules file to build the package using it if it isn't used by default.

                      Comment


                        #12
                        Re: Creating deb packages from scratch

                        There was a whole distro many years ago that required of the user to make at least one .deb him or her self because the only .debs in the repos were the ones that were (re) packaged or packaged by the method required by the distro developer.

                        The idea being that a self consistent set of .debs would be produced and maintained by the users.

                        I don't remember the name of the distro, it has fallen by the wayside, but I think that it originated in South America, although that could easily be wrong on my part.

                        Maybe someone else remembers the distro?

                        woodsmoke
                        sigpic
                        Love Thy Neighbor Baby!

                        Comment


                          #13
                          Re: Creating deb packages from scratch

                          Originally posted by rainbowsally


                          Probably only 2mb smaller (and uncompresses just as fast, though compression is slower).

                          Thanks for the comments!

                          I don't like the regular DEBIAN usr etc folder layout because it can't be used by anything else. If the DEBIAN folder is kept somewhere else the same directory tree can be used by 'make' (without any special parsing when creating the makefile) or RPM or whatever.

                          Good observations though. Thanks again.
                          I do not quite understand this. rpm doesn't care if there is a debian folder in the source, just like debbuild doesn't care if there is an rpm spec file in there. make or cmake don't care either. What is there to parse? They are not part of the actual compile process.

                          Comment


                            #14
                            Re: Creating deb packages from scratch

                            Originally posted by claydoh
                            Originally posted by rainbowsally


                            Probably only 2mb smaller (and uncompresses just as fast, though compression is slower).

                            Thanks for the comments!

                            I don't like the regular DEBIAN usr etc folder layout because it can't be used by anything else. If the DEBIAN folder is kept somewhere else the same directory tree can be used by 'make' (without any special parsing when creating the makefile) or RPM or whatever.

                            Good observations though. Thanks again.
                            I do not quite understand this. rpm doesn't care if there is a debian folder in the source, just like debbuild doesn't care if there is an rpm spec file in there. make or cmake don't care either. What is there to parse? They are not part of the actual compile process.
                            You're right, if you do it the way they want you to, which is to install, then take the file list and build the rpm from a working installation, but who wants to do that?

                            But let's back up a moment. Forget rpm (and make, which I thought I'd be having to explain rather than rpm here -- make not cmake).

                            Having the DEBIAN in the same folder with the tree makes it complicated calculating sizes for the deb control file.

                            That alone is reason enough to consider an alternative such as the one I implemented.

                            But the bottom line is that it must look like a ppa (or whatever you call it) when you use dpkg or dpkg-deb to build it.

                            That was done in my example by way of a temporary symlink which allows me to still compute sizes without having to move the control files and replace them afterward, and also allows me to use a make-based installer/uninstaller (with rollback capability !!!) and of course dpkg/dpkg-deb for the final version.

                            In any case it may be a matter of taste for some. It's a matter of convenience for me.

                            Great comments today! (about kde using lzma and stuff too.)

                            :-)

                            Comment


                              #15
                              Re: Creating deb packages from scratch

                              Hi Steve. I can't seem to find the right thread where we were talking about muon taking out kde and x11 when you uninstall something so I'll do it here.

                              Originally posted by SteveRiley
                              Have you heard of the package equivs? I'd imagine this could help partially reduce the number of steps in your procedure.
                              Hi Steve.

                              Got the data on the "dangerous muon" thing, and you're right it's the same with apt-get.

                              Apt-get gives us a bit more control so let's take a look at what happens, and this also happened in v. 12.04, which I no longer use. I'm back to 11.10.

                              For those unfamiliar with the command, the -s switch allows a simulation, not actually doing the operation which if I allowed it to complete would (and this is now utterly VERIFIED) reduce my linux to a terminal based system without even any X11.

                              Here we go.
                              $> apt-get -s install konqueror
                              NOTE: This is only a simulation!
                              apt-get needs root privileges for real execution.
                              Keep also in mind that locking is deactivated,
                              so don't depend on the relevance to the real current situation!
                              Reading package lists... Done
                              Building dependency tree
                              Reading state information... Done
                              konqueror is already the newest version.
                              You might want to run 'apt-get -f install' to correct these:
                              The following packages have unmet dependencies:
                              libc6 : Depends: libc-bin (= 2.13-20ubuntu10) but 2.13-20ubuntu5 is to be installed
                              libc6-dev : Depends: linux-libc-dev but it is not installable
                              libstdc++6 : Depends: gcc-4.6-base (= 4.6.1-9ubuntu3) but 4.6.2-5ubuntu1 is to be installed
                              E: Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).
                              [linux-libc-dev is in Casper Live, ironically, and I thought I had the uri for that offline archive right too (as I do for the DVD files) but apt-get can't see it yet for some reason.]

                              On the 12.04 DVD installation this happened with an attempt to uninstall kdevelop4 and I caught the error before rebooting (reinstalled all of X11 and kde that I needed to at least keep my desktop). On the 11.10 system this happens if I try to install konqueror using the archives on the 12.04 DVD. And as I mentioned above I verified that apt-get does NOT reinstall stuff with the right versions after unintalling everything. I had to do a full reinstall of kubuntu (saving my home folder as <username>-bak which I re-renamed after the installation was done.

                              I like that feature of the kubuntu installer, by the way. It doesn't force you to formate your partition. The downside of this, for dialup user's though, is that you MUST delete your /var folder and also the dpkg cache older if it has already been generated because the installer will hang forever (literally) if it sees those folders and can't get online.

                              Back on the ranch...

                              The 'dpkg' commands let me install konqueror. It works great (better than 12.04 did -- everything does, not just konqueror). But with dpkg it's a slow iterative process to get all the parts installed, alternating between 'dpkg -a' (to list the unconfigured packages) and 'dpkg -c' to list the problems, then 'find * -name <pkg>_*.deb' to get the full path to the file and repeating the dpkg -i operation with that full path.

                              I want to automate those operations, by the way, with a GUI app that pushes the unconfigured packages onto a stack and pops and pushes as new dependencies surface until the stack is empty or we completely bomb out... all done as simulations (I hope) until the result is success after which all the packages can be installed unconditionally with the --force-depends switch (since it's already been checked and the exact order of how the packages are installed probably doesn't matter.

                              [Working on a metapackage to try to override these two non-differing versions conflicting. They are both identical as far as I can see.]

                              Got a code snippet for fun I want to upload while we're on the subject of packages and doing stuff more-or-less by hand.

                              Comment

                              Working...
                              X