Skip to content

Commit

Permalink
checkpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
ericswanson-dfinity committed Nov 25, 2024
1 parent e256db2 commit 7cbd5c2
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 6 deletions.
84 changes: 84 additions & 0 deletions docs/extension-manifest-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@
"name": {
"type": "string"
},
"project_templates": {
"type": [
"object",
"null"
],
"additionalProperties": {
"$ref": "#/definitions/ExtensionProjectTemplate"
}
},
"subcommands": {
"anyOf": [
{
Expand Down Expand Up @@ -155,6 +164,58 @@
}
]
},
"ExtensionProjectTemplate": {
"type": "object",
"required": [
"category",
"display",
"post_create",
"requirements"
],
"properties": {
"category": {
"description": "Used to determine which CLI group (`--type`, `--backend`, `--frontend`) as well as for interactive selection",
"allOf": [
{
"$ref": "#/definitions/ProjectTemplateCategory"
}
]
},
"display": {
"description": "The name used for display and sorting",
"type": "string"
},
"post_create": {
"description": "Run a command after adding the canister to dfx.json",
"allOf": [
{
"$ref": "#/definitions/SerdeVec_for_String"
}
]
},
"post_create_failure_warning": {
"description": "If the post-create command fails, display this warning but don't fail",
"type": [
"string",
"null"
]
},
"post_create_spinner_message": {
"description": "If set, display a spinner while this command runs",
"type": [
"string",
"null"
]
},
"requirements": {
"description": "Other project templates to patch in alongside this one",
"type": "array",
"items": {
"type": "string"
}
}
}
},
"ExtensionSubcommandArgOpts": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -231,6 +292,16 @@
"$ref": "#/definitions/ExtensionSubcommandOpts"
}
},
"ProjectTemplateCategory": {
"type": "string",
"enum": [
"backend",
"frontend",
"frontend-test",
"extra",
"support"
]
},
"Range_of_uint": {
"type": "object",
"required": [
Expand All @@ -249,6 +320,19 @@
"minimum": 0.0
}
}
},
"SerdeVec_for_String": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
}
}
74 changes: 74 additions & 0 deletions e2e/tests-dfx/extension.bash
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,80 @@ EOF
assert_contains "Hello, Rust By Extension!"
}

@test "extension-defined project template replaces built-in type" {
start_webserver --directory www
EXTENSION_URL="http://localhost:$E2E_WEB_SERVER_PORT/arbitrary/extension.json"
mkdir -p www/arbitrary/downloads www/arbitrary/project_templates/a-template

cat > www/arbitrary/extension.json <<EOF
{
"name": "an-extension",
"version": "0.1.0",
"homepage": "https://github.com/dfinity/dfx-extensions",
"authors": "DFINITY",
"summary": "Test extension for e2e purposes.",
"categories": [],
"keywords": [],
"project_templates": {
"rust": {
"category": "backend",
"display": "rust by extension",
"requirements": [],
"post_create": "cargo update"
}
},
"download_url_template": "http://localhost:$E2E_WEB_SERVER_PORT/arbitrary/downloads/{{tag}}.{{archive-format}}"
}
EOF

cat > www/arbitrary/dependencies.json <<EOF
{
"0.1.0": {
"dfx": {
"version": ">=0.8.0"
}
}
}
EOF

cp -R "${BATS_TEST_DIRNAME}/../../src/dfx/assets/project_templates/rust" www/arbitrary/project_templates/rust
echo "just-proves-it-used-the-project-template" > www/arbitrary/project_templates/rust/proof.txt

ARCHIVE_BASENAME="an-extension-v0.1.0"

mkdir "$ARCHIVE_BASENAME"
cp www/arbitrary/extension.json "$ARCHIVE_BASENAME"
cp -R www/arbitrary/project_templates "$ARCHIVE_BASENAME"
tar -czf "$ARCHIVE_BASENAME".tar.gz "$ARCHIVE_BASENAME"
rm -rf "$ARCHIVE_BASENAME"

mv "$ARCHIVE_BASENAME".tar.gz www/arbitrary/downloads/

assert_command dfx extension install "$EXTENSION_URL"

find "$(dfx cache show)"/extensions -print

setup_rust

dfx new rbe --type rust --no-frontend
assert_command cat rbe/proof.txt
assert_eq "just-proves-it-used-the-project-template"

#dfx new rbc --type rust --no-frontend
echo "RBE"
cat rbe/dfx.json
find rbe -type f
#echo "RBC"
#cat rbc/dfx.json
#find rbc -type f
cd rbe || exit
#cargo update
dfx_start
assert_command dfx deploy
assert_command dfx canister call rbe_backend greet '("Rust By Extension")'
assert_contains "Hello, Rust By Extension!"
}

@test "run an extension command with a canister type defined by another extension" {
install_shared_asset subnet_type/shared_network_settings/system
dfx_start_for_nns_install
Expand Down
8 changes: 6 additions & 2 deletions src/dfx-core/src/extension/installed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,14 @@ impl InstalledExtensionManifests {
self.0.contains_key(extension)
}

pub fn loaded_templates(&self, em: &ExtensionManager) -> Vec<ProjectTemplate> {
pub fn loaded_templates(
&self,
em: &ExtensionManager,
builtin_templates: &[ProjectTemplate],
) -> Vec<ProjectTemplate> {
self.0
.values()
.flat_map(|manifest| manifest.project_templates(em))
.flat_map(|manifest| manifest.project_templates(em, builtin_templates))
.collect()
}
}
24 changes: 22 additions & 2 deletions src/dfx-core/src/extension/manifest/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,19 +120,39 @@ impl ExtensionManifest {
}
}

pub fn project_templates(&self, em: &ExtensionManager) -> Vec<ProjectTemplate> {
pub fn project_templates(
&self,
em: &ExtensionManager,
builtin_templates: &[ProjectTemplate],
) -> Vec<ProjectTemplate> {
let Some(project_templates) = self.project_templates.as_ref() else {
return vec![];
};

let extension_dir = em.get_extension_directory(&self.name);

// the default sort order is after everything built-in
let default_sort_order = builtin_templates
.iter()
.map(|t| t.sort_order)
.max()
.unwrap_or(0)
+ 1;

project_templates
.iter()
.map(|(name, template)| {
let resource_dir = extension_dir.join("project_templates").join(name);
let resource_location = ResourceLocation::Directory { path: resource_dir };
let sort_order = 6;

// keep the sort order as a built-in template of the same name,
// otherwise put it after everything else
let sort_order = builtin_templates
.iter()
.find(|t| t.name == ProjectTemplateName(name.clone()))
.map(|t| t.sort_order)
.unwrap_or(default_sort_order);

let requirements = template
.requirements
.iter()
Expand Down
5 changes: 3 additions & 2 deletions src/dfx/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,9 @@ fn get_args_altered_for_extension_run(
fn inner_main() -> DfxResult {
let em = ExtensionManager::new(dfx_version())?;
let installed_extension_manifests = em.load_installed_extension_manifests()?;
let loaded_templates = installed_extension_manifests.loaded_templates(&em);
project_templates::populate(builtin_templates(), loaded_templates);
let builtin_templates = builtin_templates();
let loaded_templates = installed_extension_manifests.loaded_templates(&em, &builtin_templates);
project_templates::populate(builtin_templates, loaded_templates);

let args = get_args_altered_for_extension_run(&installed_extension_manifests)?;

Expand Down

0 comments on commit 7cbd5c2

Please sign in to comment.