7
$\begingroup$

I want to set up a local paclet server (i.e. on my own machine, not the web), how can I do this?


Sample Reason

My very numerous group of very real friends like to work on very real projects together.

We'd like to set up local shared DropBox account to store our packages (which will of course be versioned with git), and would like to be able to load our packages via the <<PackageName` syntax.

On the other hand we do not want to put this folder on $Path or add it with PacletDirectoryAdd for control reasons.

Much better would be able to use it as if it were a local paclet server.

$\endgroup$
  • 1
    $\begingroup$ What exactly is a "local paclet server"? Is there some place I can read about it? $\endgroup$ – QuantumDot Sep 19 '17 at 1:00
  • $\begingroup$ @QuantumDot I just meant a paclet server on your local machine. I've update the question to link to an answer about paclet servers. $\endgroup$ – b3m2a1 Sep 19 '17 at 1:02
8
$\begingroup$

So the trick here is to use the file:// URL protocol:

First set up a paclet server in the standard way (see also my brief explanation here)

Next we need to set up our file:// URL properly. For example, I keep the local version of my paclet server here, before pushing it to the cloud:

serverDir =
  FileNameJoin@
   {
    $UserBaseDirectory,
    "ApplicationData",
    "WebSites",
    "PacletServer"
    };

To create an appropriate file URL we'll need to tweak the output of URLBuild like so:

serverURL =
  StringReplace["file:" -> "file://"]@
   URLBuild@
    <|
     "Scheme" -> "file",
     "Path" ->
      FileNameSplit[serverDir]
     |>;

Then we can install a paclet like so:

PacletInstall[
 "SiteBuilder",
 "Site" -> serverURL
 ]

PacletManager`Paclet[
"Name" -> "SiteBuilder", "Version" -> "1.0.8", 
 "Creator" -> "b3m2a1@gmail.com", 
 "Description" -> "Implements a configuration scheme for building and \
deploying sites a la pelican.\n  Forked from BTools.", 
 "Extensions" -> {{
   "Kernel", "Root" -> ".", "Context" -> {"SiteBuilder`"}}}, 
 "Tags" -> {"web"}, "Categories" -> {"Services"}, 
 "Location" -> "~/Library/Mathematica/Paclets/Repository/\
SiteBuilder-1.0.8"]

Note for pre-11.2:

Owing to a bug in the PacletManager that seems to have been fixed in 11.2, the file:// protocol was not appropriately supported. If you're using 11.1 or below you'll need to patch the PacletInstall functions like so:

If[$VersionNumber < 11.2,
 PacletManager`Services`Private`finishPacletSiteUpdate[
   {
    PacletManager`Private`siteURL_, 
    PacletManager`Private`file_, 
    PacletManager`Private`interactive_, 
    PacletManager`Private`async_, 
    0}
   ] := 
  PacletManager`Services`Private`finishPacletSiteUpdate[
   {
    PacletManager`Private`siteURL, 
    PacletManager`Private`file, 
    PacletManager`Private`interactive, 
    PacletManager`Private`async, 
    200}
   ];
 PacletManager`Package`getTaskData[task_] := 
  Block[{PacletManager`Private`$override = True}, 
    Replace[PacletManager`Package`getTaskData[task], 
     {
       PacletManager`Private`a_, 
       PacletManager`Private`b_, 
       PacletManager`Private`c_, 
       PacletManager`Private`d_, 
       PacletManager`Private`e_, 0, 
       PacletManager`Private`rest__} :> 
      {
       PacletManager`Private`a, 
       PacletManager`Private`b, 
       PacletManager`Private`c, 
       PacletManager`Private`d, 
       PacletManager`Private`e,
        200, 
       PacletManager`Private`rest}]
    ] /; ! TrueQ[PacletManager`Private`$override]
 ]

Helper Function:

We can wrap all of this up into a convenient local-install function:

localPacletPull[pacletName_, dir : (_String | _File)?DirectoryQ] :=

  With[{
    serverURL =
     StringReplace["file:" -> "file://"]@
      URLBuild@
       <|
        "Scheme" -> "file",
        "Path" ->
         FileNameSplit[dir]
        |>
    },
   If[$VersionNumber < 11.2,
    PacletManager`Services`Private`finishPacletSiteUpdate[
      {
       PacletManager`Private`siteURL_, 
       PacletManager`Private`file_, 
       PacletManager`Private`interactive_, 
       PacletManager`Private`async_, 
       0}
      ] := 
     PacletManager`Services`Private`finishPacletSiteUpdate[
      {
       PacletManager`Private`siteURL, 
       PacletManager`Private`file, 
       PacletManager`Private`interactive, 
       PacletManager`Private`async, 
       200}
      ];
    PacletManager`Package`getTaskData[task_] := 
     Block[{PacletManager`Private`$override = True}, 
       Replace[PacletManager`Package`getTaskData[task], 
        {
          PacletManager`Private`a_, 
          PacletManager`Private`b_, 
          PacletManager`Private`c_, 
          PacletManager`Private`d_, 
          PacletManager`Private`e_, 0, 
          PacletManager`Private`rest__} :> 
         {
          PacletManager`Private`a, 
          PacletManager`Private`b, 
          PacletManager`Private`c, 
          PacletManager`Private`d, 
          PacletManager`Private`e, 200, 
          PacletManager`Private`rest}]
       ] /; ! TrueQ[PacletManager`Private`$override]
    ];
   If[Length@PacletFind[pacletName] > 0,
    PacletUpdate[pacletName,
     "Site" -> serverURL
     ],
    PacletInstall[pacletName,
     "Site" -> serverURL
     ]
    ]
   ];

So, e.g., if I know my paclet server is at ~/Dropbox/PacletServer, I can do:

localPacletPull[paclet, "~/Dropbox/PacletServer"]

And it will install / update that paclet from my DropBox server

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.