Skip to content

Commit f6aa8c0

Browse files
authored
Merge pull request #14581 from NixOS/clone-all
nix flake clone: Support all input types
2 parents 958866b + d07c24f commit f6aa8c0

File tree

6 files changed

+35
-15
lines changed

6 files changed

+35
-15
lines changed

src/libfetchers/fetchers.cc

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "nix/fetchers/fetch-settings.hh"
77
#include "nix/fetchers/fetch-to-store.hh"
88
#include "nix/util/url.hh"
9+
#include "nix/util/archive.hh"
910

1011
#include <nlohmann/json.hpp>
1112

@@ -368,10 +369,10 @@ Input Input::applyOverrides(std::optional<std::string> ref, std::optional<Hash>
368369
return scheme->applyOverrides(*this, ref, rev);
369370
}
370371

371-
void Input::clone(const Settings & settings, const Path & destDir) const
372+
void Input::clone(const Settings & settings, ref<Store> store, const std::filesystem::path & destDir) const
372373
{
373374
assert(scheme);
374-
scheme->clone(settings, *this, destDir);
375+
scheme->clone(settings, store, *this, destDir);
375376
}
376377

377378
std::optional<std::filesystem::path> Input::getSourcePath() const
@@ -484,9 +485,19 @@ void InputScheme::putFile(
484485
throw Error("input '%s' does not support modifying file '%s'", input.to_string(), path);
485486
}
486487

487-
void InputScheme::clone(const Settings & settings, const Input & input, const Path & destDir) const
488+
void InputScheme::clone(
489+
const Settings & settings, ref<Store> store, const Input & input, const std::filesystem::path & destDir) const
488490
{
489-
throw Error("do not know how to clone input '%s'", input.to_string());
491+
if (std::filesystem::exists(destDir))
492+
throw Error("cannot clone into existing path %s", destDir);
493+
494+
auto [accessor, input2] = getAccessor(settings, store, input);
495+
496+
Activity act(*logger, lvlTalkative, actUnknown, fmt("copying '%s' to %s...", input2.to_string(), destDir));
497+
498+
auto source = sinkToSource([&](Sink & sink) { accessor->dumpPath(CanonPath::root, sink); });
499+
500+
restorePath(destDir, *source);
490501
}
491502

492503
std::optional<ExperimentalFeature> InputScheme::experimentalFeature() const

src/libfetchers/git.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,8 @@ struct GitInputScheme : InputScheme
433433
return res;
434434
}
435435

436-
void clone(const Settings & settings, const Input & input, const Path & destDir) const override
436+
void clone(const Settings & settings, ref<Store> store, const Input & input, const std::filesystem::path & destDir)
437+
const override
437438
{
438439
auto repoInfo = getRepoInfo(input);
439440

src/libfetchers/github.cc

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -457,12 +457,13 @@ struct GitHubInputScheme : GitArchiveInputScheme
457457
return DownloadUrl{parseURL(url), headers};
458458
}
459459

460-
void clone(const Settings & settings, const Input & input, const Path & destDir) const override
460+
void clone(const Settings & settings, ref<Store> store, const Input & input, const std::filesystem::path & destDir)
461+
const override
461462
{
462463
auto host = getHost(input);
463464
Input::fromURL(settings, fmt("git+https://%s/%s/%s.git", host, getOwner(input), getRepo(input)))
464465
.applyOverrides(input.getRef(), input.getRev())
465-
.clone(settings, destDir);
466+
.clone(settings, store, destDir);
466467
}
467468
};
468469

@@ -544,15 +545,16 @@ struct GitLabInputScheme : GitArchiveInputScheme
544545
return DownloadUrl{parseURL(url), headers};
545546
}
546547

547-
void clone(const Settings & settings, const Input & input, const Path & destDir) const override
548+
void clone(const Settings & settings, ref<Store> store, const Input & input, const std::filesystem::path & destDir)
549+
const override
548550
{
549551
auto host = maybeGetStrAttr(input.attrs, "host").value_or("gitlab.com");
550552
// FIXME: get username somewhere
551553
Input::fromURL(
552554
settings,
553555
fmt("git+https://%s/%s/%s.git", host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo")))
554556
.applyOverrides(input.getRef(), input.getRev())
555-
.clone(settings, destDir);
557+
.clone(settings, store, destDir);
556558
}
557559
};
558560

@@ -639,14 +641,15 @@ struct SourceHutInputScheme : GitArchiveInputScheme
639641
return DownloadUrl{parseURL(url), headers};
640642
}
641643

642-
void clone(const Settings & settings, const Input & input, const Path & destDir) const override
644+
void clone(const Settings & settings, ref<Store> store, const Input & input, const std::filesystem::path & destDir)
645+
const override
643646
{
644647
auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht");
645648
Input::fromURL(
646649
settings,
647650
fmt("git+https://%s/%s/%s", host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo")))
648651
.applyOverrides(input.getRef(), input.getRev())
649-
.clone(settings, destDir);
652+
.clone(settings, store, destDir);
650653
}
651654
};
652655

src/libfetchers/include/nix/fetchers/fetchers.hh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public:
143143

144144
Input applyOverrides(std::optional<std::string> ref, std::optional<Hash> rev) const;
145145

146-
void clone(const Settings & settings, const Path & destDir) const;
146+
void clone(const Settings & settings, ref<Store> store, const std::filesystem::path & destDir) const;
147147

148148
std::optional<std::filesystem::path> getSourcePath() const;
149149

@@ -229,7 +229,8 @@ struct InputScheme
229229

230230
virtual Input applyOverrides(const Input & input, std::optional<std::string> ref, std::optional<Hash> rev) const;
231231

232-
virtual void clone(const Settings & settings, const Input & input, const Path & destDir) const;
232+
virtual void clone(
233+
const Settings & settings, ref<Store> store, const Input & input, const std::filesystem::path & destDir) const;
233234

234235
virtual std::optional<std::filesystem::path> getSourcePath(const Input & input) const;
235236

src/nix/flake.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ struct CmdFlakeNew : CmdFlakeInitCommon
10191019

10201020
struct CmdFlakeClone : FlakeCommand
10211021
{
1022-
Path destDir;
1022+
std::filesystem::path destDir;
10231023

10241024
std::string description() override
10251025
{
@@ -1049,7 +1049,7 @@ struct CmdFlakeClone : FlakeCommand
10491049
if (destDir.empty())
10501050
throw Error("missing flag '--dest'");
10511051

1052-
getFlakeRef().resolve(fetchSettings, store).input.clone(fetchSettings, destDir);
1052+
getFlakeRef().resolve(fetchSettings, store).input.clone(fetchSettings, store, destDir);
10531053
}
10541054
};
10551055

tests/functional/flakes/flakes.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,10 @@ tar cfz "$TEST_ROOT"/flake.tar.gz -C "$TEST_ROOT" flake5
369369

370370
nix build -o "$TEST_ROOT"/result file://"$TEST_ROOT"/flake.tar.gz
371371

372+
nix flake clone "file://$TEST_ROOT/flake.tar.gz" --dest "$TEST_ROOT/unpacked"
373+
[[ -e $TEST_ROOT/unpacked/flake.nix ]]
374+
expectStderr 1 nix flake clone "file://$TEST_ROOT/flake.tar.gz" --dest "$TEST_ROOT/unpacked" | grep 'existing path'
375+
372376
# Building with a tarball URL containing a SRI hash should also work.
373377
url=$(nix flake metadata --json file://"$TEST_ROOT"/flake.tar.gz | jq -r .url)
374378
[[ $url =~ sha256- ]]

0 commit comments

Comments
 (0)