Skip to content

Commit

Permalink
feat (cli): Add fetch CLI command (with documentation)
Browse files Browse the repository at this point in the history
  • Loading branch information
vorburger committed Dec 29, 2024
1 parent 9ae6b48 commit 4331964
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .markdown-link-check.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@
{ "pattern": "^https://kohesio.ec.europa.eu" },
{ "pattern": "^https://billiam.itch.io/deepdwn" }
],
"aliveStatusCodes": [504, 503, 502, 405, 200, 0]
"aliveStatusCodes": [504, 503, 502, 405, 202, 200, 0]
}
85 changes: 85 additions & 0 deletions docs/use/fetch/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<!--
SPDX-License-Identifier: Apache-2.0
Copyright 2024 The Enola <https://enola.dev> Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

# Fetch

`fetch` fetches a _Resource_ from an _URL_ and outputs its content. You can therefore use this similarly to [curl](https://curl.se/) or [httpie](https://httpie.io/cli) or [wget](https://en.wikipedia.org/wiki/Wget). (If you want to see the _Media Type,_ use [`info detect`](../info/index.md#detect).)

This is different from [`get`](../get/index.md), which shows _Things_ given an _IRI.
(However the `--load` option of `get` internally does a `fetch`, and supports the same schemes.)

Enola supports the [URI schemes](https://en.wikipedia.org/wiki/List_of_URI_schemes) which are documented below.
These are supported everywhere; including in `fetch`, `--load`, and elsewhere.

## HTTP

This will fetch <https://www.vorburger.ch/hello.md>: _(Note how for security reasons we have to explicitly permit it.)_

```bash cd ../.././..
$ ./enola fetch --http-scheme https://www.vorburger.ch/hello.md
...
```

Enola locally caches HTTP responses on the filesystem.

## Files

We can do `cat`-like equivalent of local files using [the `file:` scheme](https://en.wikipedia.org/wiki/File_URI_scheme):

```bash cd ../.././..
$ echo "hello" >/tmp/hi.txt && ./enola fetch file:///tmp/hi.txt
...
```

We can omit the `file:` scheme and use absolute or relative paths,
because (in the CLI) the current working directory is implicitly [the _base URI_
used to resolve URI references](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#URI_references):

```bash cd ../.././..
$ ./enola fetch /tmp/hi.txt
...
```

## Classpath

```bash cd ../.././..
$ ./enola fetch classpath:/VERSION
...
```

## Data

Enola [supports (RFC 2397) `data:` URLs](https://en.m.wikipedia.org/wiki/Data_URI_scheme):

```bash cd ../.././..
$ ./enola fetch "data:application/json;charset=UTF-8,%7B%22key%22%3A+%22value%22%7D"
...
```

## Empty

`empty:` is a (non-standard) URL scheme in Enola for "no content" (as an alternative to `data:,`):

```bash cd ../.././..
$ ./enola fetch empty:/
...
```

## Screencast

![Demo](script.svg)
2 changes: 2 additions & 0 deletions docs/use/get/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,5 @@ $ ./enola get --load models/enola.dev/enola.ttl https://enola.dev/emoji | head -
```

Note that `get` [supports various formats](../help/index.md#get).

PS: The [`fetch`](../fetch/index.md) command does something related.
9 changes: 9 additions & 0 deletions docs/use/help/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@ $ ./enola help validate
...
```

## Fetch

[Fetch](../fetch/index.md) has the following options:

```bash cd ../.././..
$ ./enola help fetch
...
```

## Info

[Info](../info/index.md) has the following options:
Expand Down
18 changes: 17 additions & 1 deletion docs/use/info/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,23 @@ $ ./enola info detect --file-scheme picasso.thing.yaml
...
```

Note that this file does not exist, this is fine; the type of its content is determine by the extension (in this case).
Note that this file does not exist; that's fine,
as the type of its content is determined by the extension (in this case).
In some cases it may even be part of the URL itself, like for [`data:` URLs](../fetch/index.md#data):

```bash cd ../.././..
$ ./enola info detect "data:application/json;charset=UTF-8,%7B%22key%22%3A+%22value%22%7D"
...
```

It's also possible to "override" the Media Type, like this:

```bash cd ../.././..
./enola info detect "picasso.thing.yaml?mediaType=application/json"
...
```

[`fetch`](../fetch/index.md) is another command to "get the bytes at" an URL.

## Metadata

Expand Down
7 changes: 4 additions & 3 deletions java/dev/enola/cli/DetectCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
description =
"Provides information about the media type detected for a given URL.\n"
+ "This works both for local files (based on extension), and remote HTTP (based"
+ " on headers).")
+ " on headers).\n"
+ "See also the related 'fetch' command.")
public class DetectCommand extends CommandWithResourceProvider {

@Spec CommandSpec spec;
Expand All @@ -45,9 +46,9 @@ public void run() throws Exception {
super.run();
try (var ctx = TLC.open().push(URIs.ContextKeys.BASE, Paths.get("").toUri())) {
var resource = rp.getResource(URIs.parse(iri));
var mediaType = resource.mediaType();
var pw = spec.commandLine().getOut();
pw.println(mediaType);
pw.println(resource.mediaType());
resource.lastModifiedIfKnown().ifPresent(lastModified -> pw.println(lastModified));
}
}
}
3 changes: 2 additions & 1 deletion java/dev/enola/cli/EnolaCLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
LoggingTestCommand.class,
InfoCommand.class,
ValidateCommand.class,
CanonicalizeCommand.class
CanonicalizeCommand.class,
FetchCommand.class
})
public class EnolaCLI {

Expand Down
52 changes: 52 additions & 0 deletions java/dev/enola/cli/FetchCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2024 The Enola <https://enola.dev> Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.enola.cli;

import dev.enola.common.context.TLC;
import dev.enola.common.io.iri.URIs;

import picocli.CommandLine;

import java.net.URI;
import java.nio.file.Paths;

@CommandLine.Command(
name = "fetch",
description = {"Fetches (I/O) a Resource", "See also the related 'info detect' command."})
public class FetchCommand extends CommandWithResourceProvider {

@CommandLine.Parameters(index = "0", paramLabel = "URL", description = "URL to fetch")
String url;

@Override
public Integer call() throws Exception {
super.run();
var uri = URI.create(url);
try (var ctx = TLC.open().push(URIs.ContextKeys.BASE, Paths.get("").toUri())) {
var resource = rp.getResource(uri);
if (resource == null) {
System.err.println(uri.getScheme() + " scheme unknown; try: enola fetch --help");
return 1;

} else {
resource.byteSource().copyTo(System.out);
return 0;
}
}
}
}
1 change: 1 addition & 0 deletions java/dev/enola/common/io/iri/URIs.java
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ private static String getFragment(String uri) {

// TODO Review if getScheme(), getPath(), getQueryString(), getFragment() are *REALLY* needed?!

@Deprecated // TODO This automagic " " => %20 is fishy... who needs this, why?!
public static String encode(String uri) {
return uri.replace(" ", "%20");
}
Expand Down
5 changes: 3 additions & 2 deletions java/dev/enola/common/io/resource/EmptyResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
import java.net.URI;

/**
* Read-only resources which when read are always immediately EOF. This is a bit like /dev/null on
* *NIX OS for reading, but not for writing (because /dev/null ignores writes, whereas this fails).
* Read-only resources which when read are always immediately EOF (like "data:,"). This is a bit
* like /dev/null on *NIX OS for reading, but not for writing (because /dev/null ignores writes,
* whereas this fails).
*
* @see NullResource for an alternative that returns infinite 0s instead of EOF.
*/
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ nav:
- Canonicalize: use/canonicalize/index.md
- ExecMD: use/execmd/index.md
- Info: use/info/index.md
- Fetch: use/info/fetch.md
- Models:
- By Type: models/index.md
- By Parent: models/hierarchy.md
Expand Down

0 comments on commit 4331964

Please sign in to comment.