Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Feature request: Store multiple registered packages in a single Git repository #1251

Closed
DilumAluthge opened this issue Jul 14, 2019 · 67 comments
Assignees

Comments

@DilumAluthge
Copy link
Member

DilumAluthge commented Jul 14, 2019

Currently, a single Git repository can only contain one registered package, which must live in the top folder of the Git repository.

I would like to request the ability to store more than one registered package in the same Git repository.

For example, I might have two packages Foo and Bar that I store in a single GitHub repository DilumAluthge/FooBar.git. In this case, the contents of https://github.com/DilumAluthge/FooBar.git might look something like this:

FooBar
├── Bar
│   ├── Project.toml
│   ├── src
│   │   └── Bar.jl
│   └── test
│       └── runtests.jl
└── Foo
    ├── Project.toml
    ├── src
    │   └── Foo.jl
    └── test
        └── runtests.jl

6 directories, 6 files

For example, the contents of https://github.com/DilumAluthge/FooBar.git might instead look something like this:

FooBar
├── myfolder
│   └── Foo
│       ├── Project.toml
│       ├── src
│       │   └── Foo.jl
│       └── test
│           └── runtests.jl
└── otherfolder
    └── subfolder
        └── Bar
            ├── Project.toml
            ├── src
            │   └── Bar.jl
            └── test
                └── runtests.jl

9 directories, 6 files

Possibly related issues/pull requests:

  • Allow packages to live in a directory of repo #691: "Allow packages to live in a directory of repo"

    • This issue discusses relaxing the requirement that a package is located in the top folder of the Git repository. However, the issue doesn't discuss whether or not you would be allowed to have multiple registered packages in the same Git repository.
  • Proposal for "sub-projects". #1233: Proposal for "sub-projects"

    • This issue discusses sub-projects. However, a sub-project is an "incremental addition of packages to an already existing main-project". This is different from what I am proposing here, in which there is no "main project" from which the other projects derive.
@StefanKarpinski
Copy link
Member

As far as installing package goes, this already works. Where is the support lacking? Real question: what doesn't work when you try it?

@DilumAluthge
Copy link
Member Author

DilumAluthge commented Jul 14, 2019

I've set up a working example.


Minimum working example

The Git repository FooBar that contains both the Foo.jl and Bar.jl packages:

The registry TestRegistry:

Pkg.add works:

Each of the following code blocks runs successfully.

julia> using Pkg
julia> Pkg.Registry.add("General")
julia> Pkg.Registry.add(Pkg.RegistrySpec(url="https://github.com/DilumAluthge/TestRegistry.git"))
julia> Pkg.add("Foo")
julia> using Foo
julia> Foo.double(5)
julia> Pkg.test("Foo")
julia> using Pkg
julia> Pkg.Registry.add("General")
julia> Pkg.Registry.add(Pkg.RegistrySpec(url="https://github.com/DilumAluthge/TestRegistry.git"))
julia> Pkg.add("Bar")
julia> using Bar
julia> Bar.triple(5)
julia> Pkg.test("Bar")
julia> using Pkg
julia> Pkg.Registry.add("General")
julia> Pkg.Registry.add(Pkg.RegistrySpec(url="https://github.com/DilumAluthge/TestRegistry.git"))
julia> Pkg.add("Foo")
julia> Pkg.add("Bar")
julia> using Foo
julia> using Bar
julia> Foo.double(5)
julia> Bar.triple(5)
julia> Pkg.test("Foo")
julia> Pkg.test("Bar")

Pkg.develop does not work:

Pkg.develop("Foo") does not work:

julia> using Pkg

julia> Pkg.Registry.add("General")
   Cloning registry from "https://github.com/JuliaRegistries/General.git"
     Added registry `General` to `~/.julia/registries/General`

julia> Pkg.Registry.add(Pkg.RegistrySpec(url="https://github.com/DilumAluthge/TestRegistry.git"))
   Cloning registry from "https://github.com/DilumAluthge/TestRegistry.git"
     Added registry `TestRegistry` to `~/.julia/registries/TestRegistry`

julia> Pkg.develop("Foo")
  Updating registry at `~/.julia/registries/General`
  Updating git-repo `https://github.com/JuliaRegistries/General.git`
  Updating registry at `~/.julia/registries/TestRegistry`
  Updating git-repo `https://github.com/DilumAluthge/TestRegistry.git`
   Cloning git-repo `https://github.com/DilumAluthge/FooBar.git`
  Updating git-repo `https://github.com/DilumAluthge/FooBar.git`
 Resolving package versions...
  Updating `~/.julia/environments/v1.1/Project.toml`
  [ac29586c] + Foo v0.1.0+ [`~/.julia/dev/Foo`]
  Updating `~/.julia/environments/v1.1/Manifest.toml`
  [ac29586c] + Foo v0.1.0+ [`~/.julia/dev/Foo`]
  [2a0f44e3] + Base64
  [8ba89e20] + Distributed
  [b77e0a4c] + InteractiveUtils
  [56ddb016] + Logging
  [d6f4376e] + Markdown
  [9a3f8284] + Random
  [9e88b42a] + Serialization
  [6462fe0b] + Sockets
  [8dfed614] + Test

julia> using Foo
ERROR: ArgumentError: Package Foo [ac29586c-a683-11e9-2825-255c508e5462] is required but does not seem to be installed:
 - Run `Pkg.instantiate()` to install all recorded dependencies.

Stacktrace:
 [1] _require(::Base.PkgId) at ./loading.jl:929
 [2] require(::Base.PkgId) at ./loading.jl:858
 [3] require(::Module, ::Symbol) at ./loading.jl:853

julia> Pkg.test("Foo")
  Updating registry at `~/.julia/registries/General`
  Updating git-repo `https://github.com/JuliaRegistries/General.git`
  Updating registry at `~/.julia/registries/TestRegistry`
  Updating git-repo `https://github.com/DilumAluthge/TestRegistry.git`
ERROR: Package Foo did not provide a `test/runtests.jl` file
Stacktrace:
 [1] pkgerror(::String, ::Vararg{String,N} where N) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/Types.jl:120
 [2] #test#66(::Bool, ::Function, ::Pkg.Types.Context, ::Array{Pkg.Types.PackageSpec,1}) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/Operations.jl:1283
 [3] #test at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:0 [inlined]
 [4] #test#46(::Bool, ::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::Function, ::Pkg.Types.Context, ::Array{Pkg.Types.PackageSpec,1}) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:198
 [5] test at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:183 [inlined]
 [6] #test#45 at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:180 [inlined]
 [7] test at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:180 [inlined]
 [8] #test#44 at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:179 [inlined]
 [9] test at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:179 [inlined]
 [10] #test#43(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::Function, ::String) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:178
 [11] test(::String) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:178
 [12] top-level scope at none:0

Pkg.develop("Bar") does not work:

julia> using Pkg

julia> Pkg.Registry.add("General")
   Cloning registry from "https://github.com/JuliaRegistries/General.git"
     Added registry `General` to `~/.julia/registries/General`

julia> Pkg.Registry.add(Pkg.RegistrySpec(url="https://github.com/DilumAluthge/TestRegistry.git"))
   Cloning registry from "https://github.com/DilumAluthge/TestRegistry.git"
     Added registry `TestRegistry` to `~/.julia/registries/TestRegistry`

julia> Pkg.develop("Bar")
  Updating registry at `~/.julia/registries/General`
  Updating git-repo `https://github.com/JuliaRegistries/General.git`
  Updating registry at `~/.julia/registries/TestRegistry`
  Updating git-repo `https://github.com/DilumAluthge/TestRegistry.git`
   Cloning git-repo `https://github.com/DilumAluthge/FooBar.git`
  Updating git-repo `https://github.com/DilumAluthge/FooBar.git`
 Resolving package versions...
  Updating `~/.julia/environments/v1.1/Project.toml`
  [f73876a8] + Bar v0.1.0+ [`~/.julia/dev/Bar`]
  Updating `~/.julia/environments/v1.1/Manifest.toml`
  [f73876a8] + Bar v0.1.0+ [`~/.julia/dev/Bar`]
  [2a0f44e3] + Base64
  [8ba89e20] + Distributed
  [b77e0a4c] + InteractiveUtils
  [56ddb016] + Logging
  [d6f4376e] + Markdown
  [9a3f8284] + Random
  [9e88b42a] + Serialization
  [6462fe0b] + Sockets
  [8dfed614] + Test

julia> using Bar
ERROR: ArgumentError: Package Bar [f73876a8-a683-11e9-3353-27bcedd920b0] is required but does not seem to be installed:
 - Run `Pkg.instantiate()` to install all recorded dependencies.

Stacktrace:
 [1] _require(::Base.PkgId) at ./loading.jl:929
 [2] require(::Base.PkgId) at ./loading.jl:858
 [3] require(::Module, ::Symbol) at ./loading.jl:853

julia> Pkg.test("Bar")
  Updating registry at `~/.julia/registries/General`
  Updating git-repo `https://github.com/JuliaRegistries/General.git`
  Updating registry at `~/.julia/registries/TestRegistry`
  Updating git-repo `https://github.com/DilumAluthge/TestRegistry.git`
ERROR: Package Bar did not provide a `test/runtests.jl` file
Stacktrace:
 [1] pkgerror(::String, ::Vararg{String,N} where N) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/Types.jl:120
 [2] #test#66(::Bool, ::Function, ::Pkg.Types.Context, ::Array{Pkg.Types.PackageSpec,1}) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/Operations.jl:1283
 [3] #test at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:0 [inlined]
 [4] #test#46(::Bool, ::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::Function, ::Pkg.Types.Context, ::Array{Pkg.Types.PackageSpec,1}) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:198
 [5] test at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:183 [inlined]
 [6] #test#45 at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:180 [inlined]
 [7] test at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:180 [inlined]
 [8] #test#44 at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:179 [inlined]
 [9] test at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:179 [inlined]
 [10] #test#43(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::Function, ::String) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:178
 [11] test(::String) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:178
 [12] top-level scope at none:0

@JuliaRegistrator register does not work:

Commenting @JuliaRegistrator register on a commit in FooBar does not work. It gives the following error: Error while trying to register: File Project.toml not found. See here: https://github.com/DilumAluthge/FooBar/commit/9c7e8cf8c2d3e3a022fe4292e64171892920b265

@StefanKarpinski
Copy link
Member

Thanks @DilumAluthge, that helps push this forward considerably. So the question with Pkg.develop is: What do we want this to do? What should developing a package that is not at the root of its repo do? For Registrator, I think it's pretty straightforward: we should look for project files anywhere in the repo. However, if there's more than one, which one is supposed to be registered? I had originally envisioned that Registrator would work by just looking for commits changing the version number in any project file and then considering that commit to be a trigger for registering the new version of the package where the project file lives. @nkottaary, @KristofferC, any thoughts?

@DilumAluthge
Copy link
Member Author

What should developing a package that is not at the root of its repo do?

For developing packages that are not at the root of the repo, we could require that the user provide the path (relative from the repo root) to the package. This could be a new field in Pkg.Types.PackageSpec named subdirectory:

Pkg.develop(Pkg.PackageSpec(name = "Foo", subdirectory = "myfolder"))
Pkg.develop(Pkg.PackageSpec(name = "Bar", subdirectory = "otherfolder/subfolder"))

Alternatively, it could be a keyword argument to Pkg.develop:

Pkg.develop("Foo"; subdirectory = "myfolder")
Pkg.develop("Bar"; subdirectory = "otherfolder/subfolder")

For Registrator, I think it's pretty straightforward: we should look for project files anywhere in the repo. However, if there's more than one, which one is supposed to be registered?

For registrator, if the project file is not located in the project root, we could similarly require the user to supply the location of the package within the repo. For example, this would register Foo.jl:

@JuliaRegistrator register branch=master subdirectory=myfolder

And this would register Bar.jl:

@JuliaRegistrator register branch=master subdirectory=otherfolder/subfolder

@fredrikekre
Copy link
Member

fredrikekre commented Jul 16, 2019

For developing packages that are not at the root of the repo, we could require that the user provide the path (relative from the repo root) to the package. This could be a new field in Pkg.Types.PackageSpec named subdirectory:

It should be relatively easy to find the subdirectory by looking for the correct Project.toml file.

Edit: I guess just a URL is not enough, but url + name?

Pkg.develop(PackageSpec(name = "Foo", url = "https......"))

@KristofferC
Copy link
Member

KristofferC commented Jul 16, 2019

Thanks for the excellent summary @DilumAluthge. I personally like the explicitness of providing the relative path to the package in question. Like you said, this could be used both for Registrator and develop.

@StefanKarpinski
Copy link
Member

Aside from the keyword subdirectory being a bit long, that seems like a good option. Maybe dir= or path= or root= or subdir=? We could also support passing name= to find the project file by name. These could be alternative ways to specify. (If someone passes both, error if the package at given root doesn't have the expected name?)

Alternatively, what if used URL fragment identifiers here? I.e.

https://github.com/user/repo#path/to/package
https://github.com/user/repo#name

We could interpret the fragment as a path first, look at that path for a project file; failing that, if the name doesn't have / in it, look through all the project files for one with the fragment as a name.

@KristofferC
Copy link
Member

We kinda used # to mean branch already in the sense add url#branch.

I think it is fine to start simple with only providing the subdir option and then if we feel the need we can add more automagic ways.

@tkf
Copy link
Member

tkf commented Sep 19, 2019

How about using the query string?

https://github.com/user/repo?subdir=path/to/package
https://github.com/user/repo?name=Foo

(I'm borrowing the idea from pip https://pip.pypa.io/en/stable/reference/pip_install/#vcs-support )

@clarkevans
Copy link
Member

clarkevans commented Sep 23, 2019

This is a feature we'd also like to have. For DataKnots we'll be growing an ecosystem of adapters of various sorts. Each one of it has glue code, and it'd be rather silly to have a unique repository for each since it complicates releases and makes it harder to find what you are after. Has there been any progress lately on making this work? This topic was asked last year on the forums.

@KristofferC KristofferC self-assigned this Sep 23, 2019
@StefanKarpinski
Copy link
Member

Marking for triage to be discussed on the next Pkg call so that we can make a decision here. This shouldn't be too hard to do, we just need to decide how to express it.

@clarkevans
Copy link
Member

Hurray... there is a WIP, #1422 ;)

@fingolfin
Copy link
Member

And hurray, #1422 was merged! Progress! I am really hoping this can make it into the next LTS

@Mentors4EDU
Copy link

Mentors4EDU commented Apr 8, 2020

Also, referencing pull request #11169

@KristofferC
Copy link
Member

Implemented

@KristofferC
Copy link
Member

Yes, the current state of Flux+Adapt+Zygote+Tracker should've only been tagged together, and it's right now in a limbo state of going through PRs one by one and until then everything downstream is left with an installation that fails at using because of the random solution to dependencies that Tracker chose (it drops down to a version that isn't compatible with v1.3).

Why would an Ad library has to be tagged in lock step with Flux? And why would stuff start to fail if only one of these are tagged. This just looks like bad developer practice and has nothing to do with Pkg. Define a proper API and expose it and don't break stuff all the time?

@ChrisRackauckas
Copy link
Member

ChrisRackauckas commented Jun 21, 2020

This solves the latency times issue. The question is, what else (if anything) needs to be done to leverage the ability to shove everything into one repo to make development easier.

How do the CI triggers work? And are the dependencies per sub-package?

@timholy
Copy link
Member

timholy commented Jun 21, 2020

A script that modifies the registry to update the urls and adds a subdir entry for them.

LocalRegistry made JuliaRegistries/General#16663 easy. It might be ideal to give Registrator the ability to register multiple subdirs, but this is the least of my worries.

I don't really know what you mean about CI, in the case where you just want to merge existing packages into a single repo

While I'd certainly like to make the act of splitting or merging seamless, my biggest concern is whether we've really thought through the ongoing development cycle. As I pointed out in #1251 (comment), suppose BigPkg and all of its sub-package dependencies is at v1.8.3. Now suppose I make a breaking change and move everyone to v2.0.0. OK, so the overarching BigPkg Project.toml file (the one that Pkg first looks at) shows this:

version = "2.0.0"

[deps]
SubPkgA = "uuidA"
SubPkgB = "uuidB"

[compat]
SubPkgA = "2"
SubPkgB = "2"

When I submit this for CI, I'm reasonably sure Pkg is going to barf, because it has no idea where it will get v2 of SubPkgA from (the most recently-registered version is 1.8.3). Of course it's being defined in this same PR (SubPkgA/Project.toml also moved to version = "2.0.0" in the same PR), but I think Pkg will throw an error before it gets to the point of realizing that.

EDIT: I don't think I even needed to go to 2.0.0, I think the same thing would happen if some whiz-bang new (but non-breaking) feature were added to SubPkgA and so everyone bumps to 1.9.0.

@ChrisRackauckas
Copy link
Member

ChrisRackauckas commented Jun 21, 2020

Why would an Ad library has to be tagged in lock step with Flux? And why would stuff start to fail if only one of these are tagged. This just looks like bad developer practice and has nothing to do with Pkg. Define a proper API and expose it and don't break stuff all the time?

🤦 . It's following all of the good developer practices that were laid out for the auto-merge era. It gave an update to Adapt 2.0, an update to Zygote that wants that, and then when Pkg decides to serve that, everything else falls back to a version that was either before it used Adapt or before they used good versions, so you get a version of Tracker that brings the whole world down until all of the Adapt 2.0 updates go through, and any time you add a package that bounds Adapt 2.0 Pkg finds this as a valid solution.

So why does everything need to move in lock step? Because our good developer practices easily leads to these situations 🤷 . I can know that this nonsense leads to 2% of DiffEq failing tests, but instead, good developer practice means that 100% of DiffEq/Turing/Pumas/etc. is unusable with the current standard registry. I think the most salient issue of the current situation is that good developer practices is unable to decouple the issues of Flux from the rest of SciML because of the hard bounds. A "meh" solution isn't even possible without coordinating 50 other packages outside SciML to join in, so instead every time Flux makes a move we just have to sit back and wait for the whole ecosystem to sort itself out again.

@timholy
Copy link
Member

timholy commented Jun 21, 2020

How do the CI triggers work?

Right now I run all tests as part of the "outer" package (SnoopCompile is not huge). There, my intention is to have everything advance in lock-step. With JuliaImages (which is bigger, though not as big as your ecosystem) I might want to have the ability to run a subset of tests, not sure. We've often thought about running tests for "meta" packages when updating focused packages and vice versa, e.g., JuliaImages/Images.jl#468. I seem to remember others but can't find them now, maybe @johnnychen94 knows. Even though a CI run of everything would take quite a long time, it would have advantages.

And are the dependencies per sub-package?

Yes, in that SnoopCompile repo you can see each subpackage (just a subdirectory of the top-level repo) has its own Project.toml file. Most dependencies of the sub-packages are not declared as direct dependencies of the wrapper package.

@johnnychen94
Copy link
Member

@timholy Do you mean JuliaImages/Images.jl#805 (and probably the docs JuliaImages/Images.jl#843)

@clarkevans
Copy link
Member

I attempted to explain a package-dependency use case for DataKnots -- basically, we have glue packages we'd like in a monorepo. We would like a top-level documentation and CI tests inclusive of all optional modules (JSON, XML, SQL, etc.); this top-level need isn't a Julia package, or at least not one you'd want to install. It would be nice to be able to commit the entire ecosystem with a single version, even though they are modeled as separate Julia packages. Tim, is this similar to your situation?

@timholy
Copy link
Member

timholy commented Jun 21, 2020

Here's another example, one which you're familiar with @KristofferC. There's a big rewrite of Revise brewing in timholy/Revise.jl#497. Because Revise is used by lots of people who seem to have very different workflows, I'd really like to get some beta testers before inflicting it on the world. Revise depends on CodeTracking, JuliaInterpreter, and LoweredCodeUtils, and to make the rewrite possible all of them need changes. Because we have upper bounds---and because I know the difficult process of getting testers will be even harder if I have to tell people to dev particular branches from several different repos---I say, "I know, I can use the fact that we have upper bounds and release v1.0 of CodeTracking and LoweredCodeUtils, and Pkg will handle everything automatically."

Except it doesn't. In addition to timholy/Revise.jl#508, there's also the issue that Pkg's resolver notices the fact that it can increase the version on two packages, CodeTracking and LoweredCodeUtils, if it lowers the version of Revise to something that depends on neither. So if you happen to add CodeTracking LoweredCodeUtils Revise in a clean environment, here's what you get:

   Updating `/tmp/pkgs/environments/v1.4/Project.toml`
  [da1fd8a2] + CodeTracking v1.0.0
  [6f1432cf] + LoweredCodeUtils v1.1.2
  [295af30f] + Revise v1.0.3

Revise 1.0.3 is really old. Now, if you only add Revise this doesn't happen, but if you're a developer and you're switching between devved and freed versions of packages constantly as you develop new featuresbreak stuff and need to go back to a working version temporarily, you run into this all the time.

That why git branches feel like the right way to develop new features; if Revise, JuliaInterpreter, Debugger, CodeTracking, and LoweredCodeUtils were all part of one giant git repo, I could just say "check out this one branch" and everything is done. Then when it's time to release I can release them all, but until then I don't need to trouble the rest of the world with compatibility issues.

So I'm really excited about this new feature Pkg devs have developed! I am just pointing out that I think we're still missing some tooling to make this work properly.

@timholy
Copy link
Member

timholy commented Jun 21, 2020

Tim, is this similar to your situation?

Yes, one of them, particularly our JuliaImages ecosystem. Images is basically a meta-package. There's also the issue of our documentation, which is a separate repo and deploys docs for the whole ecosystem. We've wrestled a lot with questions like "should focused packages host their own docs, or should the whole ecosystem be documented as a whole?" Again, one of the really huge things about this new development is we won't have to make that choice any more: if all the focused packages are in the same github repo as the meta package, then there's really only one documentation site.

@fredrikekre
Copy link
Member

I still have not understood how this discussion relate to the possibility of having multiple packages in the same repo. It seems like all the same constraints apply to having the packages in multiple repos.

@timholy
Copy link
Member

timholy commented Jun 21, 2020

There are two separate points:

  • is anything more awkward than when the repos are separate?
  • are there opportunities that we're failing to take advantage of?

Based partly on the confusion of folks who understand Pkg better than I do, I've reconsidered how I'm thinking now, and I think the answer to the first one is "no." But, it's not how I thought about it when starting out to split SnoopCompile. The "right" way, as I think you're espousing, to do it is to (1) duplicate the code you need to create SubPkgA (important: do not delete the copy that lives in the old monolithic BigPkg), get it through CI, and register it; (2) after 3 days, duplicate the code you need to create SubPkgB, get it through CI, and register it; ... (n) after 3 days, delete the duplicated code from BigPkg, make it depend on all the subpackages, and register the new version. This works. But for me that was counterintuitive because my first thought was to aim for the final state I wanted, not craft the strategy in terms of how to get it past CI & Pkg registration. And of course it's very slow (but this is no different from doing it in separate repos).

The answer to the second question is "yes, we're definitely failing to take advantage of a huge opportunity to do better." To explain this point clearly, I've submitted #1874.

@ma-laforge
Copy link

It sounds like people have different views as to why sub-packages are good to have. The following describes my own use case:

Why do I want all sub-packages in a git repo to have a single "repo-wide" version number?

Because every "project" in that repo should be somewhat related, and would often build on its neighboring packages.
Consequently, it is just easier to publish a single, monolithic package that will release all sub-packages simultaneously, with the same version number.

So, it appears I have much in common with @timholy in this respect.

Side-benefit of registering all subpackages simultaneously

If everything got registered simultaneously in one PR to the GeneralRegistry, could I not trigger testing of all packages from the root package, by "adding" sub-packages to the "test" "[target]" on that root Project.toml file? That should install their dependencies correctly, and make the CI test environment ready for the sub-packages as well.

So why not just make a sigle package?

(Question from @fredrikekre #1251 (comment))

Well, since the package system pulls in (downloads, builds, etc) ALL dependencies of my monolithic package, any user of my monolithic package would be forced to suffer long download, build, and compile times. I'm also pretty sure the memory footprint and time-to-first-execution of the resulting application will blow up, as well.

So I really just need these sub-packages to limit the dependency graph without resorting to having to manage a huge amount of independent Git repos, commits, and PRs to GeneralRegistry. I intend on achiving this goal by sepearating out code that "requires" external packages to said sub-packages.

MY QUESTION:

Could this somehow be done from the "targets" section of Project.toml?????

I mean, the "test" target dependencies only just kick in when you run test, right?

Maybe we could do something similar so that using BigPkg.PkgA would trigger the build process, and import the dependencies associated with these "sub-targets" (instead of calling them subpackages)?

@KristofferC
Copy link
Member

KristofferC commented Jul 10, 2020

Registering multiple packages in a repo with a single command just requires some additions to the registration infrastructure. I think a globbing syntax like JuliaRegistrator register subdir=* was suggested at some point.

Bumping all project versions could be done with some script.

There still doesn't seems to be a need to tweak anything in Pkg for this.

@ma-laforge
Copy link

@KristofferC: You might be right.

I guess my complaint a the moment stem from the fact that I seem to be unable to develop my new multi-package module locally on my computer. That's why I described my use case above. I keep running into issues where the package manager appears to need my module to be registered in JuliaRegistries/General for things to run smoothly, for some reason.

  • If I try to make my package available through Pkg.add(path="LOCALPATH/RootPkg", subdir="subpkgs/SubPkgA"), it clones the most recent commit, so I need to commit every time I want to run a test.
  • If I try to dev SubPkgA to avoid committing for every test run, it fails. The bug originates from the fact that the add() function reads LOCALPATH/RootPkg/Project.toml and sees the wrong project name. It doesn't know to look in "subpkgs/SubPkgA/Project.toml".

(I am using Julia 1.5-rc1)

@GunnarFarneback
Copy link
Contributor

The bug originates from the fact that the add() function reads LOCALPATH/RootPkg/Project.toml and sees the wrong project name.

If there is a bug in the subdir functionality we want to find and fix it before 1.5 is released. What are the exact steps to reproduce it?

@KristofferC
Copy link
Member

I guess my complaint a the moment stem from the fact that I seem to be unable to develop my new multi-package module locally on my computer.

I don't get that. Just dev all the packages. Just like always.

Could you make a MWE that shows the problem?

@ma-laforge
Copy link

Yes, I saw that dev all package one-liner that @timholy posted on the other issue. I haven't tried that yet.

Note that it does seem counter-intuitive to have to dev all packages when you technically shouldn't be aware that your repo hosts multiple packages in the currently supported workflow.

I'll try creating a MWE for you, though. I got the vague impression it was already known. Sorry.

@ma-laforge
Copy link

Ok. I built a sample multi-package repo on Github, to illustrate my MWE.

You can add PkgTestRoot, SubPkgA, and SubPkgB using the following:

Pkg.add(path="https://github.com/ma-laforge/PkgTestRoot.jl")
Pkg.add(path="https://github.com/ma-laforge/PkgTestRoot.jl", subdir="subpkgs/SubPkgA.jl")
Pkg.add(path="https://github.com/ma-laforge/PkgTestRoot.jl", subdir="subpkgs/SubPkgB.jl")

Now, if I want to modify one of the sub-packages, I would logically do the following:

]dev SubPkgA

But in Julia 1.5.0-rc1.0, I get the following error:

ERROR: name `PkgTestRoot` given by project file `/home/laforge/.julia/dev/SubPkgA/Project.toml` does not match given name `SubPkgA`

So it "dev"s the entire repo under the name SubPkgA, then assumes (incorrectly) that the root Project.toml file corresponds to that sub package. That's why it sees a name mismatch. It should have checked the other Project.toml file.

@GunnarFarneback
Copy link
Contributor

Thanks, I can reproduce this.

So the scenario here is developing an unregistered subdir package by name, which is known to Pkg after having been added by URL. Clearly the code is not doing the right thing here and I've opened #1925 to track it. Meanwhile, the easiest workaround is probably to develop the subdir URL shown by Pkg.status:

(@v1.5) pkg> st
Status `/tmp/foo16/environments/v1.5/Project.toml`
  [f50ccdc4] PkgTestRoot v0.1.0 `https://github.com/ma-laforge/PkgTestRoot.jl#master`
  [2176828e] SubPkgA v0.1.0 `https://github.com/ma-laforge/PkgTestRoot.jl:subpkgs/SubPkgA.jl#master`
  [b3c70a09] SubPkgB v0.1.0 `https://github.com/ma-laforge/PkgTestRoot.jl:subpkgs/SubPkgB.jl#master`

(@v1.5) pkg> dev https://github.com/ma-laforge/PkgTestRoot.jl:subpkgs/SubPkgA.jl

@ma-laforge
Copy link

Thanks @GunnarFarneback. Yes that appears to work!

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests