66#include " archive.hh"
77#include " tarfile.hh"
88#include " types.hh"
9+ #include " split.hh"
910
1011namespace nix ::fetchers {
1112
@@ -168,24 +169,34 @@ std::pair<Tree, time_t> downloadTarball(
168169 };
169170}
170171
171- struct TarballInputScheme : InputScheme
172+ // An input scheme corresponding to a curable ressource
173+ struct CurlInputScheme : InputScheme
172174{
173- std::optional<Input> inputFromURL (const ParsedURL & url) override
175+ virtual const std::string inputType () const = 0;
176+ const std::set<std::string> transportUrlSchemes = {" file" , " http" , " https" };
177+
178+ const bool hasTarballExtension (std::string_view path) const
174179 {
175- if (url.scheme != " file" && url.scheme != " http" && url.scheme != " https" ) return {};
180+ return hasSuffix (path, " .zip" ) || hasSuffix (path, " .tar" )
181+ || hasSuffix (path, " .tgz" ) || hasSuffix (path, " .tar.gz" )
182+ || hasSuffix (path, " .tar.xz" ) || hasSuffix (path, " .tar.bz2" )
183+ || hasSuffix (path, " .tar.zst" );
184+ }
176185
177- if (!hasSuffix (url.path , " .zip" )
178- && !hasSuffix (url.path , " .tar" )
179- && !hasSuffix (url.path , " .tgz" )
180- && !hasSuffix (url.path , " .tar.gz" )
181- && !hasSuffix (url.path , " .tar.xz" )
182- && !hasSuffix (url.path , " .tar.bz2" )
183- && !hasSuffix (url.path , " .tar.zst" ))
184- return {};
186+ virtual bool isValidURL (const ParsedURL & url) const = 0;
187+
188+ std::optional<Input> inputFromURL (const ParsedURL & url) override
189+ {
190+ if (!isValidURL (url))
191+ return std::nullopt ;
185192
186193 Input input;
187- input.attrs .insert_or_assign (" type" , " tarball" );
188- input.attrs .insert_or_assign (" url" , url.to_string ());
194+
195+ auto urlWithoutApplicationScheme = url;
196+ urlWithoutApplicationScheme.scheme = parseUrlScheme (url.scheme ).transport ;
197+
198+ input.attrs .insert_or_assign (" type" , inputType ());
199+ input.attrs .insert_or_assign (" url" , urlWithoutApplicationScheme.to_string ());
189200 auto narHash = url.query .find (" narHash" );
190201 if (narHash != url.query .end ())
191202 input.attrs .insert_or_assign (" narHash" , narHash->second );
@@ -194,29 +205,27 @@ struct TarballInputScheme : InputScheme
194205
195206 std::optional<Input> inputFromAttrs (const Attrs & attrs) override
196207 {
197- if (maybeGetStrAttr (attrs, " type" ) != " tarball" ) return {};
208+ auto type = maybeGetStrAttr (attrs, " type" );
209+ if (type != inputType ()) return {};
198210
211+ std::set<std::string> allowedNames = {" type" , " url" , " narHash" , " name" , " unpack" };
199212 for (auto & [name, value] : attrs)
200- if (name != " type " && name != " url " && /* name != "hash" && */ name != " narHash " && name != " name " )
201- throw Error (" unsupported tarball input attribute '%s'" , name);
213+ if (!allowedNames. count ( name) )
214+ throw Error (" unsupported %s input attribute '%s'" , *type , name);
202215
203216 Input input;
204217 input.attrs = attrs;
218+
205219 // input.locked = (bool) maybeGetStrAttr(input.attrs, "hash");
206220 return input;
207221 }
208222
209223 ParsedURL toURL (const Input & input) override
210224 {
211225 auto url = parseURL (getStrAttr (input.attrs , " url" ));
212- // NAR hashes are preferred over file hashes since tar/zip files
213- // don't have a canonical representation.
226+ // NAR hashes are preferred over file hashes since tar/zip files // don't have a canonical representation.
214227 if (auto narHash = input.getNarHash ())
215228 url.query .insert_or_assign (" narHash" , narHash->to_string (SRI, true ));
216- /*
217- else if (auto hash = maybeGetStrAttr(input.attrs, "hash"))
218- url.query.insert_or_assign("hash", Hash(*hash).to_string(SRI, true));
219- */
220229 return url;
221230 }
222231
@@ -225,6 +234,42 @@ struct TarballInputScheme : InputScheme
225234 return true ;
226235 }
227236
237+ };
238+
239+ struct FileInputScheme : CurlInputScheme
240+ {
241+ const std::string inputType () const override { return " file" ; }
242+
243+ bool isValidURL (const ParsedURL & url) const override
244+ {
245+ auto parsedUrlScheme = parseUrlScheme (url.scheme );
246+ return transportUrlSchemes.count (std::string (parsedUrlScheme.transport ))
247+ && (parsedUrlScheme.application
248+ ? parsedUrlScheme.application .value () == inputType ()
249+ : !hasTarballExtension (url.path ));
250+ }
251+
252+ std::pair<StorePath, Input> fetch (ref<Store> store, const Input & input) override
253+ {
254+ auto file = downloadFile (store, getStrAttr (input.attrs , " url" ), input.getName (), false );
255+ return {std::move (file.storePath ), input};
256+ }
257+ };
258+
259+ struct TarballInputScheme : CurlInputScheme
260+ {
261+ const std::string inputType () const override { return " tarball" ; }
262+
263+ bool isValidURL (const ParsedURL & url) const override
264+ {
265+ auto parsedUrlScheme = parseUrlScheme (url.scheme );
266+
267+ return transportUrlSchemes.count (std::string (parsedUrlScheme.transport ))
268+ && (parsedUrlScheme.application
269+ ? parsedUrlScheme.application .value () == inputType ()
270+ : hasTarballExtension (url.path ));
271+ }
272+
228273 std::pair<StorePath, Input> fetch (ref<Store> store, const Input & input) override
229274 {
230275 auto tree = downloadTarball (store, getStrAttr (input.attrs , " url" ), input.getName (), false ).first ;
@@ -233,5 +278,6 @@ struct TarballInputScheme : InputScheme
233278};
234279
235280static auto rTarballInputScheme = OnStartup([] { registerInputScheme (std::make_unique<TarballInputScheme>()); });
281+ static auto rFileInputScheme = OnStartup([] { registerInputScheme (std::make_unique<FileInputScheme>()); });
236282
237283}
0 commit comments