Skip to content

Commit

Permalink
feat: support find kcl files from 'workdir'. (#689)
Browse files Browse the repository at this point in the history
* feat: support find kcl files from 'workdir'.

* fix: fix CR comments.

* fix: fix CR comments.

* fix: add test case.
  • Loading branch information
zong-zhe authored Aug 31, 2023
1 parent 396c473 commit 24ca285
Show file tree
Hide file tree
Showing 16 changed files with 96 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ubuntu_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ./kclvm/.kclvm/lcov.info
path-to-lcov: ./kclvm/.kclvm_cov/lcov.info

- uses: actions/upload-artifact@v3
with:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ lark_parser.pickle

# KCLVM cache and temp output
.kclvm
.kclvm_cov
*.dylib
*.so
*.dll
Expand Down
5 changes: 5 additions & 0 deletions kclvm/cmd/src/test_data/instances/test_inst_11/kcl.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
name = "test_inst_11"
edition = "0.0.1"
version = "0.0.1"

3 changes: 3 additions & 0 deletions kclvm/cmd/src/test_data/instances/test_inst_11/model/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
schema K11:
msg: str

5 changes: 5 additions & 0 deletions kclvm/cmd/src/test_data/instances/test_inst_11/sub/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import model as m

k11_inst: m.K11 {
msg: "k11_in_sub"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
k11_inst:
msg: k11_in_main
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
name = "test_inst_111"
edition = "0.0.1"
version = "0.0.1"

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kcl_cli_configs:
file:
- ../sub/main.k
- ./main.k
package_maps:
test_inst_11: ./src/test_data/instances/test_inst_11
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import test_inst_11.model as m

k11_inst: m.K11 {
msg= "k11_in_main"
}
1 change: 1 addition & 0 deletions kclvm/cmd/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ fn test_instances_with_yaml() {
"test_inst_8",
"test_inst_9",
"test_inst_10",
"test_inst_11/test_inst_111",
];

for case in &test_cases {
Expand Down
10 changes: 6 additions & 4 deletions kclvm/config/src/modfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub struct KCLModFileExpectedSection {
pub global_version: Option<String>,
}

pub fn get_pkg_root_from_paths(file_paths: &[String]) -> Result<String, String> {
pub fn get_pkg_root_from_paths(file_paths: &[String], workdir: String) -> Result<String, String> {
if file_paths.is_empty() {
return Err("No input KCL files or paths".to_string());
}
Expand All @@ -107,6 +107,8 @@ pub fn get_pkg_root_from_paths(file_paths: &[String]) -> Result<String, String>
}
if m.len() == 1 {
return Ok(last_root);
} else if !workdir.is_empty() {
return Ok(workdir);
}

Err(format!("conflict kcl.mod file paths: {:?}", m))
Expand Down Expand Up @@ -162,17 +164,17 @@ mod modfile_test {
#[test]
fn test_get_pkg_root_from_paths() {
assert_eq!(
get_pkg_root_from_paths(&[]),
get_pkg_root_from_paths(&[], "".to_string()),
Err("No input KCL files or paths".to_string())
);
assert_eq!(
get_pkg_root_from_paths(&["wrong_path".to_string()]),
get_pkg_root_from_paths(&["wrong_path".to_string()], "".to_string()),
Ok("".to_string())
);
let expected_root = std::path::Path::new(TEST_ROOT).canonicalize().unwrap();
let expected = expected_root.adjust_canonicalization();
assert_eq!(
get_pkg_root_from_paths(&[SETTINGS_FILE.to_string()]),
get_pkg_root_from_paths(&[SETTINGS_FILE.to_string()], "".to_string()),
Ok(expected.to_string())
);
}
Expand Down
2 changes: 1 addition & 1 deletion kclvm/driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ pub fn canonicalize_input_files(
}

// Get the root path of the project
let pkgroot = kclvm_config::modfile::get_pkg_root_from_paths(&kcl_paths)?;
let pkgroot = kclvm_config::modfile::get_pkg_root_from_paths(&kcl_paths, work_dir)?;

// The second traversal replaces ${KCL_MOD} with the project root path
kcl_paths = kcl_paths
Expand Down
5 changes: 3 additions & 2 deletions kclvm/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ codecov:
codecov-lcov:
rustup component add llvm-tools-preview
cargo install cargo-llvm-cov
mkdir $(PWD)/.kclvm
cargo llvm-cov --lcov --output-path $(PWD)/.kclvm/lcov.info --workspace --ignore-filename-regex gpyrpc.rs -- --nocapture
rm -rf $(PWD)/.kclvm_cov
mkdir $(PWD)/.kclvm_cov
cargo llvm-cov --lcov --output-path $(PWD)/.kclvm_cov/lcov.info --workspace --ignore-filename-regex gpyrpc.rs -- --nocapture

# Test runtime libaries using python functions
test-runtime: install-kclvm-py install-pytest
Expand Down
88 changes: 49 additions & 39 deletions kclvm/parser/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::LoadProgramOptions;
/// The reason why the [`Entries`] is not an [`IndexMap`] is that the [`entries`] is duplicable and ordered.
#[derive(Default, Debug)]
pub struct Entries {
root_path: String,
entries: VecDeque<Entry>,
}

Expand Down Expand Up @@ -109,6 +110,11 @@ impl Entries {
self.entries.iter_mut().try_for_each(f)?;
return Ok(());
}

/// [`get_root_path`] will return the root path of [`Entries`].
pub fn get_root_path(&self) -> &String {
&self.root_path
}
}

/// [`Entry`] is a package name and package root path pair.
Expand Down Expand Up @@ -345,50 +351,54 @@ pub fn get_compile_entries_from_paths(
result.push_entry(entry);
}

// The main 'kcl.mod' path can be found only once.
// Replace all the '${KCL_MOD}' with the real path of main 'kcl.mod'.
if result
let pkg_root = if result
.get_unique_normal_paths_by_name(kclvm_ast::MAIN_PKG)
.len()
== 1
&& opts.work_dir.is_empty()
{
// If the [`ModRelativePath`] with preffix '${KCL_MOD}'.
// Replace the '${KCL_MOD}' by the root path of package '__main__'.

// Calculate the root path of package '__main__'.
let pkg_root;
let main_entry = result
.get_nth_entry_by_name(0, kclvm_ast::MAIN_PKG)
.ok_or_else(|| format!("program entry not found in {:?}", file_paths))?;
pkg_root = main_entry.path().to_string();

// Replace the '${KCL_MOD}' of all the paths with package name '__main__'.
result.apply_to_all_entries(|entry| {
let path = ModRelativePath::from(entry.path().to_string());
if entry.name() == kclvm_ast::MAIN_PKG
&& path.is_relative_path().map_err(|err| err.to_string())?
{
entry.set_path(pkg_root.to_string());
entry.extend_k_files(get_main_files_from_pkg_path(
&path
.canonicalize_by_root_path(&pkg_root)
.map_err(|err| err.to_string())?,
&pkg_root,
&kclvm_ast::MAIN_PKG.to_string(),
opts,
)?);
}
return Ok(());
})?;
return Ok(result);
}
// If the 'kcl.mod' can be found only once, the package root path will be the path of the 'kcl.mod'.
result
.get_unique_normal_paths_by_name(kclvm_ast::MAIN_PKG)
.get(0)
.unwrap()
.to_string()
} else if !opts.work_dir.is_empty() {
// If the 'kcl.mod' can be found more than once, the package root path will be the 'work_dir'.
if let Some(root_work_dir) = get_pkg_root(&opts.work_dir) {
root_work_dir
} else {
"".to_string()
}
} else {
// If there are more than one main 'kcl.mod' files, return error.
// the root path of package '__main__' can only one.
return Err(format!(
"conflict kcl.mod file paths: {:?}",
result.get_unique_normal_paths_by_name(kclvm_ast::MAIN_PKG)
));
};
result.root_path = pkg_root.clone();
// Replace the '${KCL_MOD}' of all the paths with package name '__main__'.
result.apply_to_all_entries(|entry| {
let path = ModRelativePath::from(entry.path().to_string());
if entry.name() == kclvm_ast::MAIN_PKG
&& path.is_relative_path().map_err(|err| err.to_string())?
{
entry.set_path(pkg_root.to_string());
entry.extend_k_files(get_main_files_from_pkg_path(
&path
.canonicalize_by_root_path(&pkg_root)
.map_err(|err| err.to_string())?,
&pkg_root,
&kclvm_ast::MAIN_PKG.to_string(),
opts,
)?);
}
return Ok(());
})?;

// If there are more than one main 'kcl.mod' files, return error.
// the root path of package '__main__' can only one.
Err(format!(
"conflict kcl.mod file paths: {:?}",
result.get_unique_normal_paths_by_name(kclvm_ast::MAIN_PKG)
))
return Ok(result);
}

/// Get files in the main package with the package root.
Expand Down
7 changes: 2 additions & 5 deletions kclvm/parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,7 @@ impl Loader {
fn _load_main(&mut self) -> Result<ast::Program, String> {
let compile_entries = get_compile_entries_from_paths(&self.paths, &self.opts)?;
let mut pkgs = HashMap::new();

let main_program_root = compile_entries
.contains_pkg_name(&kclvm_ast::MAIN_PKG.to_string())
.ok_or(format!("main package not found in {:?}", &self.paths))?;
let workdir = compile_entries.get_root_path().to_string();

debug_assert_eq!(compile_entries.len(), self.paths.len());

Expand Down Expand Up @@ -349,7 +346,7 @@ impl Loader {
// Insert the complete ast to replace the empty list.
pkgs.insert(kclvm_ast::MAIN_PKG.to_string(), pkg_files);
Ok(ast::Program {
root: main_program_root.path().to_string(),
root: workdir,
main: kclvm_ast::MAIN_PKG.to_string(),
pkgs,
})
Expand Down
2 changes: 1 addition & 1 deletion kclvm/tools/src/LSP/src/request.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anyhow::Ok;
use crossbeam_channel::Sender;

use lsp_types::TextEdit;
use ra_ap_vfs::VfsPath;
use std::time::Instant;
Expand Down

0 comments on commit 24ca285

Please sign in to comment.