feat: Display full recipe with syntax highlighting (#166)
As I was re-arranging my recipe files, I needed a way to ensure that the
order of my recipe is correct without having to read through the
generated `Containerfile`. So I added a `-d`/`--display-full-recipe` arg
to `template` that will print out all of your modules in the order
defined by following the `from-file` property.
```
$> bluebuild template --help
Generate a Containerfile from a recipe
Usage: bluebuild template [OPTIONS] [RECIPE]
Arguments:
[RECIPE]
The recipe file to create a template from
Options:
-o, --output <OUTPUT>
File to output to instead of STDOUT
--registry <REGISTRY>
The registry domain the image will be published to.
This is used for modules that need to know where the image is being published (i.e. the signing module).
--registry-namespace <REGISTRY_NAMESPACE>
The registry namespace the image will be published to.
This is used for modules that need to know where the image is being published (i.e. the signing module).
-d, --display-full-recipe
Instead of creating a Containerfile, display the full recipe after traversing all `from-file` properties.
This can be used to help debug the order you defined your recipe.
-t, --syntax-theme <SYNTAX_THEME>
Choose a theme for the syntax highlighting for the Containerfile or Yaml.
The default is `mocha-dark`.
[possible values: mocha-dark, ocean-dark, ocean-light, eighties-dark, inspired-github, solarized-dark, solarized-light]
-s, --squash
Puts the build in a `squash-stage` and COPY's the results to the final stage as one layer.
WARN: This doesn't work with the docker driver as it has been deprecated.
NOTE: Squash has a performance benefit for the newer versions of podman and buildah.
-B, --build-driver <BUILD_DRIVER>
Select which driver to use to build your image
[possible values: buildah, podman, docker]
-v, --verbose...
Increase logging verbosity
-I, --inspect-driver <INSPECT_DRIVER>
Select which driver to use to inspect images
[possible values: skopeo, podman, docker]
-q, --quiet...
Decrease logging verbosity
-h, --help
Print help (see a summary with '-h')
```
Preview of Containerfile/Dockerfile syntax highlighting:

Preview of Yaml highlighting:

This commit is contained in:
parent
a7503d561e
commit
92150693d4
9 changed files with 477 additions and 9 deletions
179
Cargo.lock
generated
179
Cargo.lock
generated
|
|
@ -2,6 +2,12 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
|
|
@ -127,12 +133,29 @@ dependencies = [
|
|||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||
|
||||
[[package]]
|
||||
name = "basic-toml"
|
||||
version = "0.1.8"
|
||||
|
|
@ -142,6 +165,15 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
|
@ -223,7 +255,9 @@ name = "blue-build-utils"
|
|||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"atty",
|
||||
"chrono",
|
||||
"clap",
|
||||
"colored",
|
||||
"directories",
|
||||
"env_logger",
|
||||
|
|
@ -233,6 +267,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml 0.9.32",
|
||||
"syntect",
|
||||
"which",
|
||||
]
|
||||
|
||||
|
|
@ -400,6 +435,15 @@ version = "0.8.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.25.0"
|
||||
|
|
@ -522,6 +566,22 @@ version = "2.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4556222738635b7a3417ae6130d8f52201e45a0c4d1a907f0826383adb5f85e7"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
|
|
@ -610,6 +670,15 @@ version = "0.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.9"
|
||||
|
|
@ -790,6 +859,12 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "line-wrap"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd1bc4d24ad230d21fb898d1116b1801d7adfc449d42026475862ab48b11e70e"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
|
|
@ -846,6 +921,15 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.10"
|
||||
|
|
@ -910,6 +994,28 @@ version = "1.19.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "onig"
|
||||
version = "6.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"onig_sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "onig_sys"
|
||||
version = "69.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "open"
|
||||
version = "5.0.1"
|
||||
|
|
@ -979,6 +1085,20 @@ version = "0.3.30"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||
|
||||
[[package]]
|
||||
name = "plist"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9d34169e64b3c7a80c8621a48adaf44e0cf62c78a9b25dd9dd35f1881a17cf9"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"indexmap 2.2.3",
|
||||
"line-wrap",
|
||||
"quick-xml",
|
||||
"serde",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
|
|
@ -1005,6 +1125,15 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.35"
|
||||
|
|
@ -1156,6 +1285,15 @@ version = "1.0.16"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
|
|
@ -1316,6 +1454,28 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syntect"
|
||||
version = "5.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags 1.3.2",
|
||||
"flate2",
|
||||
"fnv",
|
||||
"once_cell",
|
||||
"onig",
|
||||
"plist",
|
||||
"regex-syntax",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.10.0"
|
||||
|
|
@ -1601,6 +1761,16 @@ version = "0.9.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
|
@ -1690,6 +1860,15 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ version = "0.8.4"
|
|||
[workspace.dependencies]
|
||||
anyhow = "1"
|
||||
chrono = "0.4.35"
|
||||
clap = { version = "4", features = ["derive", "cargo", "unicode"] }
|
||||
colored = "2.1.0"
|
||||
env_logger = "0.11"
|
||||
format_serde_error = "0.3.0"
|
||||
|
|
@ -54,7 +55,6 @@ pre-release-replacements = [
|
|||
blue-build-recipe = { version = "=0.8.4", path = "./recipe" }
|
||||
blue-build-template = { version = "=0.8.4", path = "./template" }
|
||||
blue-build-utils = { version = "=0.8.4", path = "./utils" }
|
||||
clap = { version = "4", features = ["derive", "cargo", "unicode"] }
|
||||
clap-verbosity-flag = "2"
|
||||
clap_complete = "4"
|
||||
clap_complete_nushell = "4"
|
||||
|
|
@ -71,6 +71,7 @@ users = "0.11.0"
|
|||
# Workspace dependencies
|
||||
anyhow.workspace = true
|
||||
chrono.workspace = true
|
||||
clap.workspace = true
|
||||
colored.workspace = true
|
||||
env_logger.workspace = true
|
||||
log.workspace = true
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ pub struct Recipe<'a> {
|
|||
#[builder(setter(into))]
|
||||
pub image_version: Cow<'a, str>,
|
||||
|
||||
#[serde(alias = "blue-build-tag")]
|
||||
#[serde(alias = "blue-build-tag", skip_serializing_if = "Option::is_none")]
|
||||
#[builder(default, setter(into, strip_option))]
|
||||
pub blue_build_tag: Option<Cow<'a, str>>,
|
||||
|
||||
|
|
|
|||
|
|
@ -6,9 +6,12 @@ use std::{
|
|||
use anyhow::Result;
|
||||
use blue_build_recipe::Recipe;
|
||||
use blue_build_template::{ContainerFileTemplate, Template};
|
||||
use blue_build_utils::constants::{
|
||||
CI_PROJECT_NAME, CI_PROJECT_NAMESPACE, CI_REGISTRY, CONFIG_PATH, GITHUB_REPOSITORY_OWNER,
|
||||
RECIPE_FILE, RECIPE_PATH,
|
||||
use blue_build_utils::{
|
||||
constants::{
|
||||
CI_PROJECT_NAME, CI_PROJECT_NAMESPACE, CI_REGISTRY, CONFIG_PATH, GITHUB_REPOSITORY_OWNER,
|
||||
RECIPE_FILE, RECIPE_PATH,
|
||||
},
|
||||
syntax_highlighting::{self, DefaultThemes},
|
||||
};
|
||||
use clap::Args;
|
||||
use log::{debug, info, trace, warn};
|
||||
|
|
@ -46,6 +49,23 @@ pub struct TemplateCommand {
|
|||
#[builder(default, setter(into, strip_option))]
|
||||
registry_namespace: Option<String>,
|
||||
|
||||
/// Instead of creating a Containerfile, display
|
||||
/// the full recipe after traversing all `from-file` properties.
|
||||
///
|
||||
/// This can be used to help debug the order
|
||||
/// you defined your recipe.
|
||||
#[arg(short, long)]
|
||||
#[builder(default)]
|
||||
display_full_recipe: bool,
|
||||
|
||||
/// Choose a theme for the syntax highlighting
|
||||
/// for the Containerfile or Yaml.
|
||||
///
|
||||
/// The default is `mocha-dark`.
|
||||
#[arg(short = 't', long)]
|
||||
#[builder(default, setter(strip_option))]
|
||||
syntax_theme: Option<DefaultThemes>,
|
||||
|
||||
#[clap(flatten)]
|
||||
#[builder(default)]
|
||||
drivers: DriverArgs,
|
||||
|
|
@ -78,12 +98,21 @@ impl TemplateCommand {
|
|||
}
|
||||
});
|
||||
|
||||
info!("Templating for recipe at {}", recipe_path.display());
|
||||
|
||||
debug!("Deserializing recipe");
|
||||
let recipe_de = Recipe::parse(&recipe_path)?;
|
||||
trace!("recipe_de: {recipe_de:#?}");
|
||||
|
||||
if self.display_full_recipe {
|
||||
if let Some(output) = self.output.as_ref() {
|
||||
std::fs::write(output, serde_yaml::to_string(&recipe_de)?)?;
|
||||
} else {
|
||||
syntax_highlighting::print_ser(&recipe_de, "yml", self.syntax_theme)?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
info!("Templating for recipe at {}", recipe_path.display());
|
||||
|
||||
let template = ContainerFileTemplate::builder()
|
||||
.os_version(Driver::get_os_version(&recipe_de)?)
|
||||
.build_id(Driver::get_build_id())
|
||||
|
|
@ -101,10 +130,9 @@ impl TemplateCommand {
|
|||
std::fs::write(output, output_str)?;
|
||||
} else {
|
||||
debug!("Templating to stdout");
|
||||
println!("{output_str}");
|
||||
syntax_highlighting::print(&output_str, "Dockerfile", self.syntax_theme)?;
|
||||
}
|
||||
|
||||
info!("Finished templating Containerfile");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,10 @@ license.workspace = true
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
atty = "0.2.14"
|
||||
directories = "5"
|
||||
process_control = { version = "4.0.3", features = ["crossbeam-channel"] }
|
||||
syntect = "5.2.0"
|
||||
which = "6"
|
||||
|
||||
anyhow.workspace = true
|
||||
|
|
@ -23,6 +25,13 @@ serde.workspace = true
|
|||
serde_yaml.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
[dependencies.clap]
|
||||
workspace = true
|
||||
features = ["derive"]
|
||||
|
||||
[build-dependencies]
|
||||
syntect = "5.2.0"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
|
|
|
|||
24
utils/build.rs
Normal file
24
utils/build.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use syntect::dumps;
|
||||
use syntect::parsing::syntax_definition::SyntaxDefinition;
|
||||
use syntect::parsing::SyntaxSetBuilder;
|
||||
|
||||
fn main() {
|
||||
let mut ssb = SyntaxSetBuilder::new();
|
||||
ssb.add(
|
||||
SyntaxDefinition::load_from_str(
|
||||
include_str!("highlights/Dockerfile.sublime-syntax"),
|
||||
true,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
let ss = ssb.build();
|
||||
|
||||
dumps::dump_to_uncompressed_file(
|
||||
&ss,
|
||||
PathBuf::from(env::var("OUT_DIR").unwrap()).join("docker_syntax.bin"),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
141
utils/highlights/Dockerfile.sublime-syntax
Normal file
141
utils/highlights/Dockerfile.sublime-syntax
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
%YAML 1.2
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright 2014 Asbjorn Enge
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
# https://github.com/asbjornenge/Docker.tmbundle
|
||||
---
|
||||
# http://www.sublimetext.com/docs/3/syntax.html
|
||||
name: Dockerfile
|
||||
scope: source.dockerfile
|
||||
|
||||
file_extensions:
|
||||
- Dockerfile
|
||||
- dockerfile
|
||||
|
||||
hidden_file_extensions:
|
||||
- .Dockerfile
|
||||
|
||||
first_line_match: ^\s*(?i:(from(?!\s+\S+\s+import)|arg))\s+
|
||||
|
||||
variables:
|
||||
onbuild_directive: (?i:(onbuild)\s+)?
|
||||
onbuild_commands_directive:
|
||||
"{{onbuild_directive}}(?i:add|arg|env|expose|healthcheck|label|run|shell|stopsignal|user|volume|workdir)"
|
||||
nononbuild_commands_directive: (?i:maintainer)
|
||||
runtime_directive: "{{onbuild_directive}}(?i:cmd|entrypoint)"
|
||||
from_directive: (?i:(from))\s+[^\s:@]+(?:[:@](\S+))?(?:\s+(?i:(as))\s+(\S+))?
|
||||
copy_directive: ({{onbuild_directive}}(?i:copy))(?:\s+--from=(\S+))?
|
||||
|
||||
contexts:
|
||||
main:
|
||||
- include: comments
|
||||
- match: ^(?i:arg)\s
|
||||
scope: keyword.control.dockerfile
|
||||
- include: from
|
||||
|
||||
from:
|
||||
- match: ^{{from_directive}}
|
||||
captures:
|
||||
1: keyword.control.dockerfile
|
||||
2: entity.name.enum.tag-digest
|
||||
3: keyword.control.dockerfile
|
||||
4: variable.stage-name
|
||||
push: body
|
||||
|
||||
body:
|
||||
- include: comments
|
||||
- include: directives
|
||||
- include: invalid
|
||||
- include: from
|
||||
|
||||
directives:
|
||||
- match: ^\s*{{onbuild_commands_directive}}\s
|
||||
captures:
|
||||
0: keyword.control.dockerfile
|
||||
1: keyword.other.special-method.dockerfile
|
||||
push: args
|
||||
- match: ^\s*{{nononbuild_commands_directive}}\s
|
||||
scope: keyword.control.dockerfile
|
||||
push: args
|
||||
- match: ^\s*{{copy_directive}}\s
|
||||
captures:
|
||||
1: keyword.control.dockerfile
|
||||
2: keyword.other.special-method.dockerfile
|
||||
3: variable.stage-name
|
||||
push: args
|
||||
- match: ^\s*{{runtime_directive}}\s
|
||||
captures:
|
||||
0: keyword.operator.dockerfile
|
||||
1: keyword.other.special-method.dockerfile
|
||||
push: args
|
||||
|
||||
escaped-char:
|
||||
- match: \\.
|
||||
scope: constant.character.escaped.dockerfile
|
||||
|
||||
args:
|
||||
- include: comments
|
||||
- include: escaped-char
|
||||
- match: ^\s*$
|
||||
- match: \\\s+$
|
||||
- match: \n
|
||||
pop: true
|
||||
- match: '"'
|
||||
scope: punctuation.definition.string.begin.dockerfile
|
||||
push: double_quote_string
|
||||
- match: "'"
|
||||
scope: punctuation.definition.string.begin.dockerfile
|
||||
push: single_quote_string
|
||||
|
||||
double_quote_string:
|
||||
- meta_scope: string.quoted.double.dockerfile
|
||||
- include: escaped-char
|
||||
- match: ^\s*$
|
||||
- match: \\\s+$
|
||||
- match: \n
|
||||
set: invalid
|
||||
- match: '"'
|
||||
scope: punctuation.definition.string.end.dockerfile
|
||||
pop: true
|
||||
|
||||
single_quote_string:
|
||||
- meta_scope: string.quoted.single.dockerfile
|
||||
- include: escaped-char
|
||||
- match: ^\s*$
|
||||
- match: \\\s+$
|
||||
- match: \n
|
||||
set: invalid
|
||||
- match: "'"
|
||||
scope: punctuation.definition.string.end.dockerfile
|
||||
pop: true
|
||||
|
||||
comments:
|
||||
- match: ^(\s*)((#).*$\n?)
|
||||
comment: comment.line
|
||||
captures:
|
||||
1: punctuation.whitespace.comment.leading.dockerfile
|
||||
2: comment.dockerfile
|
||||
3: punctuation.definition.comment.dockerfile
|
||||
|
||||
invalid:
|
||||
- match: ^[^A-Z\n](.*)$
|
||||
scope: invalid
|
||||
set: body
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
pub mod command_output;
|
||||
pub mod constants;
|
||||
pub mod logging;
|
||||
pub mod syntax_highlighting;
|
||||
|
||||
use std::{ffi::OsStr, io::Write, path::PathBuf, process::Command, thread, time::Duration};
|
||||
|
||||
|
|
|
|||
85
utils/src/syntax_highlighting.rs
Normal file
85
utils/src/syntax_highlighting.rs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use clap::ValueEnum;
|
||||
use log::trace;
|
||||
use serde::ser::Serialize;
|
||||
use syntect::{dumps, easy::HighlightLines, highlighting::ThemeSet, parsing::SyntaxSet};
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, ValueEnum)]
|
||||
pub enum DefaultThemes {
|
||||
#[default]
|
||||
MochaDark,
|
||||
OceanDark,
|
||||
OceanLight,
|
||||
EightiesDark,
|
||||
InspiredGithub,
|
||||
SolarizedDark,
|
||||
SolarizedLight,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for DefaultThemes {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match *self {
|
||||
Self::MochaDark => "base16-mocha.dark",
|
||||
Self::OceanDark => "base16-ocean.dark",
|
||||
Self::OceanLight => "base16-ocean.light",
|
||||
Self::EightiesDark => "base16-eighties.dark",
|
||||
Self::InspiredGithub => "InspiredGithub",
|
||||
Self::SolarizedDark => "Solarized (dark)",
|
||||
Self::SolarizedLight => "Solarized (light)",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints the file with syntax highlighting.
|
||||
///
|
||||
/// # Errors
|
||||
/// Will error if the theme doesn't exist, the syntax doesn't exist, or the file
|
||||
/// failed to serialize.
|
||||
pub fn print(file: &str, file_type: &str, theme: Option<DefaultThemes>) -> Result<()> {
|
||||
trace!("syntax_highlighting::print({file}, {file_type}, {theme:?})");
|
||||
|
||||
if atty::is(atty::Stream::Stdout) {
|
||||
let ss: SyntaxSet = if file_type == "dockerfile" || file_type == "Dockerfile" {
|
||||
dumps::from_uncompressed_data(include_bytes!(concat!(
|
||||
env!("OUT_DIR"),
|
||||
"/docker_syntax.bin"
|
||||
)))?
|
||||
} else {
|
||||
SyntaxSet::load_defaults_newlines()
|
||||
};
|
||||
let ts = ThemeSet::load_defaults();
|
||||
|
||||
let syntax = ss
|
||||
.find_syntax_by_extension(file_type)
|
||||
.ok_or_else(|| anyhow!("Failed to get syntax"))?;
|
||||
let mut h = HighlightLines::new(
|
||||
syntax,
|
||||
ts.themes
|
||||
.get(theme.unwrap_or_default().to_string().as_str())
|
||||
.ok_or_else(|| anyhow!("Failed to get highlight theme"))?,
|
||||
);
|
||||
for line in file.lines() {
|
||||
let ranges = h.highlight_line(line, &ss)?;
|
||||
let escaped = syntect::util::as_24_bit_terminal_escaped(&ranges, false);
|
||||
println!("{escaped}");
|
||||
}
|
||||
println!("\x1b[0m");
|
||||
} else {
|
||||
println!("{file}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Takes a serializable struct and prints it out with syntax highlighting.
|
||||
///
|
||||
/// # Errors
|
||||
/// Will error if the theme doesn't exist, the syntax doesn't exist, or the file
|
||||
/// failed to serialize.
|
||||
pub fn print_ser<T: Serialize>(
|
||||
file: &T,
|
||||
file_type: &str,
|
||||
theme: Option<DefaultThemes>,
|
||||
) -> Result<()> {
|
||||
print(serde_yaml::to_string(file)?.as_str(), file_type, theme)?;
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue