Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

View route from server #201

Merged
merged 6 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,17 +1,38 @@
use std::borrow::Cow;

macro_rules! escape {
($escaped:ident, $bytes:literal, $s:ident, $i:ident, $len:literal) => {
match &mut $escaped {
None => {
let mut vec = Vec::with_capacity($s.len() + $len);
vec.extend_from_slice(&$s.as_bytes()[0..$i]);
vec.extend_from_slice($bytes);
$escaped = Some(vec);
macro_rules! escape_impl {
( $s:ident, $($byte:literal => $escaped:literal),* $(,)?) => {
// An ASCII byte always represent a ASCII character
// so it is safe to treat the input as bytes
{
let s = $s;
let mut escaped = None;
for (i, b) in s.bytes().enumerate() {
match b {
$(
$byte => match &mut escaped {
None => {
let mut vec = Vec::with_capacity(s.len() + $escaped.len());
vec.extend_from_slice(&s.as_bytes()[0..i]);
vec.extend_from_slice($escaped);
escaped = Some(vec);
}
Some(vec) => vec.extend_from_slice($escaped),
}
)*
_ => {
if let Some(vec) = &mut escaped {
vec.push(b);
}
}
}
}
match escaped {
Some(vec) => Cow::Owned(String::from_utf8(vec).unwrap()),
None => Cow::Borrowed(s),
}
Some(vec) => vec.extend_from_slice($bytes),
}
};
}
}

/// Escapes a string for XML.
Expand All @@ -23,36 +44,32 @@ macro_rules! escape {
/// - `"` becomes `"`
/// - `'` becomes `'`
pub fn xml_escape(s: &str) -> Cow<str> {
// An ASCII byte always represent a ASCII character
// so it is safe to treat the input as bytes
let mut escaped = None;
for (i, b) in s.bytes().enumerate() {
match b {
b'&' => {
escape!(escaped, b"&amp;", s, i, 5);
}
b'<' => {
escape!(escaped, b"&lt;", s, i, 5);
}
b'>' => {
escape!(escaped, b"&gt;", s, i, 5);
}
b'\'' => {
escape!(escaped, b"&apos;", s, i, 5);
}
b'"' => {
escape!(escaped, b"&quot;", s, i, 5);
}
_ => {
if let Some(vec) = &mut escaped {
vec.push(b);
}
}
}
escape_impl! {
s,
b'&' => b"&amp;",
b'<' => b"&lt;",
b'>' => b"&gt;",
b'\'' => b"&apos;",
b'"' => b"&quot;",
}
match escaped {
Some(vec) => Cow::Owned(String::from_utf8(vec).unwrap()),
None => Cow::Borrowed(s),
}

/// Escapes a string for HTML attribute value
///
/// This function escapes the following characters:
/// - `&` becomes `&amp;`
/// - `<` becomes `&lt;`
/// - `>` becomes `&gt;`
/// - `"` becomes `&quot;`
/// - `'` becomes `&#39;`
pub fn html_attr_escape(s: &str) -> Cow<str> {
escape_impl! {
s,
b'&' => b"&amp;",
b'<' => b"&lt;",
b'>' => b"&gt;",
b'\'' => b"&#39;",
b'"' => b"&quot;",
}
}

Expand Down
4 changes: 2 additions & 2 deletions compiler-base/src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

mod string_map;
pub use string_map::*;
mod xml_escape;
pub use xml_escape::*;
mod escape;
pub use escape::*;

// re-exports
pub use uni_path::{Component, Path, PathBuf};
2 changes: 1 addition & 1 deletion docs/src/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default defineConfig({
{ rel: "icon", href: "/static/celer-3.svg", type: "image/svg+xml" },
],
// Color
["meta", { property: "theme-color", content: "rgb(173,255,184)" }],
["meta", { property: "theme-color", content: "#adfeb8" }],
// Open Graph
[
"meta",
Expand Down
115 changes: 105 additions & 10 deletions docs/src/route/publish.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,115 @@
# Publish the Route
:::info
Incomplete. Tracked by [TODO #26](https://github.com/Pistonite/celer/issues/26)
To publish or share your route, you need to upload it to [GitHub](https://github.com).
Everyone can then view it on Celer.
:::tip
You need a GitHub account for this. If you are already familiar with Git, you can skip to the bottom of the page which tells you how to view the route
once uploaded.
:::
To publish or share your route, you need to upload it to GitHub. Everyone can then use Celer to view it. You need a GitHub account for this.

## How it works (Git basics)
1. You will create a repository on GitHub, which will become a copy of your project on GitHub.
2. Upload (push) your local folder to the repository.
3. When someone views a published route on Celer, Celer queries GitHub for the route files
4. When you want to update the route, change the files and push those changes to GitHub.
5. Everyone will see the updated route on Celer.
If you aren't familiar with git, don't worry. This page will guide you through all the steps. The general idea is:

1. You create a so-called repository (repo for short) on GitHub that will store the project.
2. You create a folder on your PC that is linked to the repository on GitHub. This process is known as "clone".
3. You move your project files inside the cloned repository.
4. You upload those files to the repository on GitHub. This process is known as "push".
5. Make future updates in the local repository and push again to upload the changes.


## Creating the repository
1. Go to https://github.com/new to start creating a new repository
2. Enter a name under `Repository name`. Note the following:
- It is the best for your repository name to only contain alphanumeric characters (`a-z`, `A-Z` and `0-9`), `_` and `-`. Special characters like `%` or unicode characters will cause inconvienience.
3. Enter a description (e.g. "My Awesome Celer Project")
3. Make sure the new repository will be `public`. Celer cannot access your private repositories.
4.
4. Check "Add a README file".
5. Click "Create repository"

## Cloning the repository
You can either clone the repository with the `git` CLI tool, or use a GUI tool like GitHub Desktop.
It is recommended to use GitHub Desktop if you don't know how or aren't comfortable running commands in a terminal.

### With GIT Command line tool
:::tip
If you are on windows, you can install `git` [here](https://git-scm.com/download/win)
:::
With `git` installed, run the following command in the directory where you want to store all your repos.
Replace `YOUR_USER_NAME` with your GitHub username and `YOUR_REPO_NAME` with the name you entered in step 2 above.

```bash
git clone git@github.com:YOUR_USER_NAME/YOUR_REPO_NAME
```

### With GitHub Desktop
Install GitHub Desktop from [here](https://desktop.github.com/). Then open it and sign in with your GitHub account.

1. Click on "Clone a repository from the internet"
2. Search for the repository you just created
3. Choose a path on your PC where you want the repo to be cloned.
4. Click "Clone"

## Move your project inside the repository
Once the repo is cloned, you should see a directory `.git` inside it on your PC and a `README.md` file.

You can simply copy and paste the project files you have been editing to the repository. The `project.yaml`
file should be at the root, next to the `README.md` file.

## Push your files
### With GIT Command line tool
First stage your changes
```bash
git add .
```
Then commit them with a message
```bash
git commit -m "example message"
```
Then push the changes
```bash
git push
```

### With GitHub Desktop
1. In GitHub Desktop, it should show the local changes you made in the "Changes" panel on the left.
Select the files you want to upload.
2. At the bottom of the changes panel, enter a short message describing the change. This is known as a commit message.
3. Click "Commit to main"
4. Now the changes panel should say "0 changed files"
5. On the top, you should see something like this:
![image of push origin](https://cdn.discordapp.com/attachments/951389021114871819/1209290318076444723/image.png?ex=65e6625f&is=65d3ed5f&hm=dab6cefc2abbd3f7796c8298cdb50bd6299dbf4c39ef30af5f8452e86cc43bba&)
6. Click that, and your commits are now uploaded. You can go to the repository on GitHub to confirm.

## Viewing the route on Celer
To view the route on celer, go to the URL below. Replace the placeholders with your GitHub username and repo name
```
scheme://celer.placeholder.domain/view/YOUR_USER_NAME/YOUR_REPO_NAME
```

### Viewing entry point
If you configured the project as a monorepo with the `entry-points` property, as described [here](./file-structure.md),
the URL above will take you to the `default` entry point. You can add an entry point to the URL to view a particular entry point.

For example, say your root `project.yaml` has:
```yaml
entry-points:
my-sub-project: /path/to/project.yaml
```
You can view `my-sub-project` as
```
scheme://celer.placeholder.domain/view/YOUR_USER_NAME/YOUR_REPO_NAME/my-sub-project
```

You can also refer to the target `project.yaml` directly:
```
scheme://celer.placeholder.domain/view/YOUR_USER_NAME/YOUR_REPO_NAME/path/to/project.yaml
```

### Viewing specific branch/commit/tag
You can add `:BRANCH` to the end of the URL to view the route at a particular branch, commit, or tag. The default is the `main` branch when you don't specify one.

For example, let's say you created a branch `v1.2`, you can refer to this branch as
```
scheme://celer.placeholder.domain/view/YOUR_USER_NAME/YOUR_REPO_NAME:v1.2
scheme://celer.placeholder.domain/view/YOUR_USER_NAME/YOUR_REPO_NAME/ENTRY_POINT:v1.2
```

This can be useful for versioning your route
1 change: 1 addition & 0 deletions docs/src/toolbar.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ These options are disabled until a document is loaded
- <FluentIcon name="ListBarTree20Regular"/> `Jump to section`: Scroll the document to a particular section.
- <FluentIcon name="DocumentError20Regular" /> `View diagnostics`: Quickly jump to a line where there is an error, warning, or info message.
- <FluentIcon name="ArrowDownload20Regular" /> `Export`: Export data from the document, such as split files. See [Export](./export.md) for more details.
- <FluentIcon name="ArrowSync20Regular" /> `Reload Document`: Reload the document from server.

## Map Options
:::tip
Expand Down
15 changes: 13 additions & 2 deletions server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ path = "../compiler-core"
features = ["native"]
default-features = false

# tower
[dependencies.tower]
version = "0.4.13"

[dependencies.tower-http]
version = "0.5.1"
features = [
"fs",
"trace",
"compression-gzip",
"set-header"
]

[dependencies]
axum = "0.7.4"
axum-macros = "0.4.1"
Expand All @@ -18,8 +31,6 @@ envconfig = "0.10.0"
futures = "0.3.28"
http-body = "0.4.5"
tokio = { version = "1.36.0", features=["macros", "rt-multi-thread"] }
tower = "0.4.13"
tower-http = { version = "0.5.1", features = ["fs", "trace", "compression-gzip"] }
tracing = "0.1.37"
tracing-subscriber = { version = "0.3.17", features = ["ansi"] }
flate2 = "1.0.28"
Expand Down
13 changes: 9 additions & 4 deletions server/src/api/compile.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! The `/compile` API endpoint.

use axum::extract::Path;
use axum::routing::get;
use axum::routing;
use axum::{Json, Router};
use instant::Instant;
use serde::{Deserialize, Serialize};
Expand All @@ -9,12 +11,15 @@ use tower_http::compression::CompressionLayer;

use crate::compiler;

pub fn init_compile_api() -> Router {
pub fn init_api() -> Router {
Router::new()
.route("/:owner/:repo/:reference", get(compile_owner_repo_ref))
.route(
"/:owner/:repo/:reference",
routing::get(compile_owner_repo_ref),
)
.route(
"/:owner/:repo/:reference/*path",
get(compile_owner_repo_ref_path),
routing::get(compile_owner_repo_ref_path),
)
.layer(ServiceBuilder::new().layer(CompressionLayer::new()))
}
Expand Down
19 changes: 14 additions & 5 deletions server/src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
use std::io;

use axum::{routing, Router};
use tracing::info;

use crate::env;

mod compile;
mod view;

pub fn init_api(router: Router) -> Router {
pub fn init_api(router: Router, app_dir: &str) -> Result<Router, io::Error> {
info!("initializing api routes");
router.nest("/api/v1", init_api_v1())
let router = router
.nest("/api/v1", init_api_v1()?)
.nest("/view", view::init_api(app_dir)?);

Ok(router)
}

pub fn init_api_v1() -> Router {
Router::new()
pub fn init_api_v1() -> Result<Router, io::Error> {
let router = Router::new()
.route("/version", routing::get(|| async { env::version() }))
.nest("/compile", compile::init_compile_api())
.nest("/compile", compile::init_api());

Ok(router)
}
Loading