Skip to content

Commit d285de0

Browse files
authored
Merge pull request #674 from gauge-sh/exclusive-interfaces
Support 'exclusive' interfaces
2 parents c29737f + 044ae09 commit d285de0

File tree

17 files changed

+105
-133
lines changed

17 files changed

+105
-133
lines changed

python/tests/example/many_features/real_src/module1/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .api import MyApi
1+
from .api import something
22

33
from module3 import content
44

python/tests/example/many_features/real_src/module1/tach.domain.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ visibility = ["<domain_root>", "//module5"]
1414
layer = "mid"
1515

1616
[[interfaces]]
17-
expose = [".*"]
17+
expose = ["something"]
1818
from = ["api"]
19-
visibility = ["<domain_root>"]
2019

2120
[[interfaces]]
2221
expose = ["MyAPI"]
2322
from = ["api"]
2423
visibility = ["//module5"]
24+
exclusive = true
2525

2626
[[modules]]
2727
path = "submodule1"

src/checks/interface.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ impl<'a> InterfaceChecker<'a> {
6666
return InterfaceCheckResult::TopLevelModule;
6767
}
6868

69-
let matching_interfaces = self.interfaces.get_interfaces(definition_module);
69+
let matching_interfaces = self
70+
.interfaces
71+
.get_visible_interfaces(definition_module, usage_module);
7072

7173
if matching_interfaces.is_empty() {
7274
return InterfaceCheckResult::NoInterfaces;

src/config/cache.rs

+3-13
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
11
use pyo3::prelude::*;
22
use serde::{Deserialize, Serialize};
33

4+
use super::utils;
5+
46
#[derive(Debug, Serialize, Default, Deserialize, Clone, PartialEq)]
57
#[serde(rename_all = "lowercase")]
68
pub enum CacheBackend {
79
#[default]
810
Disk,
911
}
1012

11-
impl CacheBackend {
12-
fn is_default(&self) -> bool {
13-
*self == Self::default()
14-
}
15-
}
16-
1713
impl IntoPy<PyObject> for CacheBackend {
1814
fn into_py(self, py: Python) -> PyObject {
1915
match self {
@@ -25,16 +21,10 @@ impl IntoPy<PyObject> for CacheBackend {
2521
#[derive(Debug, Serialize, Default, Deserialize, Clone, PartialEq)]
2622
#[pyclass(get_all, module = "tach.extension")]
2723
pub struct CacheConfig {
28-
#[serde(default, skip_serializing_if = "CacheBackend::is_default")]
24+
#[serde(default, skip_serializing_if = "utils::is_default")]
2925
pub backend: CacheBackend,
3026
#[serde(default, skip_serializing_if = "Vec::is_empty")]
3127
pub file_dependencies: Vec<String>,
3228
#[serde(default, skip_serializing_if = "Vec::is_empty")]
3329
pub env_dependencies: Vec<String>,
3430
}
35-
36-
impl CacheConfig {
37-
pub fn is_default(&self) -> bool {
38-
*self == Self::default()
39-
}
40-
}

src/config/domain.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::iter;
2+
use std::ops::Not;
23
use std::path::{Path, PathBuf};
34

45
use pyo3::prelude::*;
@@ -9,7 +10,6 @@ use crate::filesystem::file_to_module_path;
910
use super::edit::{ConfigEdit, ConfigEditor, EditError};
1011
use super::interfaces::InterfaceConfig;
1112
use super::modules::{deserialize_modules, serialize_modules, DependencyConfig, ModuleConfig};
12-
use super::utils::*;
1313
use crate::parsing::error::ParsingError;
1414

1515
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
@@ -23,9 +23,9 @@ pub struct DomainRootConfig {
2323
pub layer: Option<String>,
2424
#[serde(default)]
2525
pub visibility: Option<Vec<String>>,
26-
#[serde(default, skip_serializing_if = "is_false")]
26+
#[serde(default, skip_serializing_if = "Not::not")]
2727
pub utility: bool,
28-
#[serde(default, skip_serializing_if = "is_false")]
28+
#[serde(default, skip_serializing_if = "Not::not")]
2929
pub unchecked: bool,
3030
}
3131

@@ -183,7 +183,8 @@ impl Resolvable<InterfaceConfig> for InterfaceConfig {
183183
})
184184
.collect(),
185185
visibility: self.visibility.clone().map(|vis| vis.resolve(location)),
186-
data_types: self.data_types.clone(),
186+
data_types: self.data_types,
187+
exclusive: self.exclusive,
187188
}
188189
}
189190
}

src/config/external.rs

-6
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,3 @@ pub struct ExternalDependencyConfig {
99
#[serde(default, skip_serializing_if = "Vec::is_empty")]
1010
pub rename: Vec<String>,
1111
}
12-
13-
impl ExternalDependencyConfig {
14-
pub fn is_default(&self) -> bool {
15-
*self == Self::default()
16-
}
17-
}

src/config/interfaces.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
use std::fmt::Display;
2+
use std::ops::Not;
23

34
use pyo3::prelude::*;
45
use serde::{Deserialize, Serialize};
56

6-
#[derive(Debug, Serialize, Default, Deserialize, Clone, PartialEq)]
7+
use super::utils;
8+
9+
#[derive(Debug, Serialize, Default, Deserialize, Clone, Copy, PartialEq)]
710
#[serde(rename_all = "lowercase")]
811
pub enum InterfaceDataTypes {
912
#[default]
@@ -20,12 +23,6 @@ impl Display for InterfaceDataTypes {
2023
}
2124
}
2225

23-
impl InterfaceDataTypes {
24-
fn is_default(&self) -> bool {
25-
*self == Self::default()
26-
}
27-
}
28-
2926
impl IntoPy<PyObject> for InterfaceDataTypes {
3027
fn into_py(self, py: Python) -> PyObject {
3128
self.to_string().to_object(py)
@@ -45,8 +42,10 @@ pub struct InterfaceConfig {
4542
pub from_modules: Vec<String>,
4643
#[serde(default)]
4744
pub visibility: Option<Vec<String>>,
48-
#[serde(default, skip_serializing_if = "InterfaceDataTypes::is_default")]
45+
#[serde(default, skip_serializing_if = "utils::is_default")]
4946
pub data_types: InterfaceDataTypes,
47+
#[serde(default, skip_serializing_if = "Not::not")]
48+
pub exclusive: bool,
5049
}
5150

5251
fn default_from_modules() -> Vec<String> {

src/config/modules.rs

+14-13
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
1-
use crate::filesystem::module_path_is_included_in_paths;
2-
3-
use super::root_module::ROOT_MODULE_SENTINEL_TAG;
4-
use super::utils::*;
5-
use crate::resolvers::ModuleGlob;
6-
use globset::GlobMatcher;
7-
use pyo3::prelude::*;
8-
use serde::ser::{Error, SerializeSeq, SerializeStruct};
9-
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
101
use std::hash::{Hash, Hasher};
2+
use std::ops::Not;
113
use std::path::PathBuf;
124
use std::{
135
collections::{HashMap, HashSet},
146
fmt,
157
};
168

9+
use globset::GlobMatcher;
10+
use pyo3::prelude::*;
11+
use serde::ser::{Error, SerializeSeq, SerializeStruct};
12+
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
13+
14+
use super::root_module::ROOT_MODULE_SENTINEL_TAG;
15+
use crate::filesystem::module_path_is_included_in_paths;
16+
use crate::resolvers::ModuleGlob;
17+
1718
#[derive(Clone, Debug, Default)]
1819
#[pyclass(module = "tach.extension")]
1920
pub struct DependencyConfig {
@@ -169,7 +170,7 @@ pub struct ModuleConfig {
169170
#[serde(default)]
170171
#[pyo3(get)]
171172
pub visibility: Option<Vec<String>>,
172-
#[serde(default, skip_serializing_if = "is_false")]
173+
#[serde(default, skip_serializing_if = "Not::not")]
173174
#[pyo3(get)]
174175
pub utility: bool,
175176
// TODO: Remove this in a future version
@@ -179,7 +180,7 @@ pub struct ModuleConfig {
179180
#[serde(default, skip_serializing)]
180181
#[pyo3(get)]
181182
pub strict: bool,
182-
#[serde(default, skip_serializing_if = "is_false")]
183+
#[serde(default, skip_serializing_if = "Not::not")]
183184
#[pyo3(get)]
184185
pub unchecked: bool,
185186
// Hidden field to track grouping
@@ -390,9 +391,9 @@ struct BulkModule {
390391
layer: Option<String>,
391392
#[serde(default)]
392393
visibility: Option<Vec<String>>,
393-
#[serde(default, skip_serializing_if = "is_false")]
394+
#[serde(default, skip_serializing_if = "Not::not")]
394395
utility: bool,
395-
#[serde(default, skip_serializing_if = "is_false")]
396+
#[serde(default, skip_serializing_if = "Not::not")]
396397
unchecked: bool,
397398
}
398399

src/config/plugins/all.rs

-6
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,3 @@ pub struct PluginsConfig {
99
#[serde(default)]
1010
pub django: Option<DjangoConfig>,
1111
}
12-
13-
impl PluginsConfig {
14-
pub fn is_default(&self) -> bool {
15-
*self == Self::default()
16-
}
17-
}

src/config/plugins/django.rs

-6
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,3 @@ pub struct DjangoConfig {
77
#[serde(default)]
88
pub settings_module: String,
99
}
10-
11-
impl DjangoConfig {
12-
pub fn is_default(&self) -> bool {
13-
*self == Self::default()
14-
}
15-
}

src/config/project.rs

+17-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use pyo3::prelude::*;
22
use serde::{Deserialize, Serialize};
33
use std::iter;
4+
use std::ops::Not;
45
use std::path::PathBuf;
56

67
use crate::exclusion::PathExclusions;
@@ -17,7 +18,7 @@ use super::modules::{deserialize_modules, serialize_modules, DependencyConfig, M
1718
use super::plugins::PluginsConfig;
1819
use super::root_module::RootModuleTreatment;
1920
use super::rules::RulesConfig;
20-
use super::utils::*;
21+
use super::utils;
2122

2223
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2324
pub struct PyProjectWrapper {
@@ -49,13 +50,13 @@ pub struct ProjectConfig {
4950
#[serde(default)]
5051
#[pyo3(get)]
5152
pub interfaces: Vec<InterfaceConfig>,
52-
#[serde(default, skip_serializing_if = "is_empty")]
53+
#[serde(default, skip_serializing_if = "Vec::is_empty")]
5354
#[pyo3(get)]
5455
pub layers: Vec<String>,
55-
#[serde(default, skip_serializing_if = "CacheConfig::is_default")]
56+
#[serde(default, skip_serializing_if = "utils::is_default")]
5657
#[pyo3(get)]
5758
pub cache: CacheConfig,
58-
#[serde(default, skip_serializing_if = "ExternalDependencyConfig::is_default")]
59+
#[serde(default, skip_serializing_if = "utils::is_default")]
5960
#[pyo3(get)]
6061
pub external: ExternalDependencyConfig,
6162
#[serde(default)]
@@ -64,31 +65,34 @@ pub struct ProjectConfig {
6465
#[serde(default = "default_source_roots")]
6566
#[pyo3(get, set)]
6667
pub source_roots: Vec<PathBuf>,
67-
#[serde(default, skip_serializing_if = "is_false")]
68+
#[serde(default, skip_serializing_if = "Not::not")]
6869
#[pyo3(get)]
6970
pub exact: bool,
70-
#[serde(default, skip_serializing_if = "is_false")]
71+
#[serde(default, skip_serializing_if = "Not::not")]
7172
#[pyo3(get)]
7273
pub disable_logging: bool,
73-
#[serde(default = "default_true", skip_serializing_if = "is_true")]
74+
#[serde(
75+
default = "utils::default_true",
76+
skip_serializing_if = "utils::is_true"
77+
)]
7478
#[pyo3(get, set)]
7579
pub ignore_type_checking_imports: bool,
76-
#[serde(default, skip_serializing_if = "is_false")]
80+
#[serde(default, skip_serializing_if = "Not::not")]
7781
#[pyo3(get, set)]
7882
pub include_string_imports: bool,
79-
#[serde(default, skip_serializing_if = "is_false")]
83+
#[serde(default, skip_serializing_if = "Not::not")]
8084
#[pyo3(get)]
8185
pub forbid_circular_dependencies: bool,
82-
#[serde(default, skip_serializing_if = "is_false")]
86+
#[serde(default, skip_serializing_if = "Not::not")]
8387
#[pyo3(get, set)]
8488
pub use_regex_matching: bool,
85-
#[serde(default, skip_serializing_if = "RootModuleTreatment::is_default")]
89+
#[serde(default, skip_serializing_if = "utils::is_default")]
8690
#[pyo3(get)]
8791
pub root_module: RootModuleTreatment,
88-
#[serde(default, skip_serializing_if = "RulesConfig::is_default")]
92+
#[serde(default, skip_serializing_if = "utils::is_default")]
8993
#[pyo3(get)]
9094
pub rules: RulesConfig,
91-
#[serde(default, skip_serializing_if = "PluginsConfig::is_default")]
95+
#[serde(default, skip_serializing_if = "utils::is_default")]
9296
#[pyo3(get)]
9397
pub plugins: PluginsConfig,
9498
#[serde(skip)]

src/config/root_module.rs

-6
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,6 @@ pub enum RootModuleTreatment {
1313
DependenciesOnly,
1414
}
1515

16-
impl RootModuleTreatment {
17-
pub fn is_default(&self) -> bool {
18-
*self == Self::default()
19-
}
20-
}
21-
2216
impl IntoPy<PyObject> for RootModuleTreatment {
2317
fn into_py(self, py: Python) -> PyObject {
2418
match self {

src/config/rules.rs

-6
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,3 @@ impl Default for RulesConfig {
7575
}
7676
}
7777
}
78-
79-
impl RulesConfig {
80-
pub fn is_default(&self) -> bool {
81-
*self == Self::default()
82-
}
83-
}

src/config/utils.rs

+2-10
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,10 @@ pub fn default_true() -> bool {
33
true
44
}
55

6-
pub fn global_visibility() -> Vec<String> {
7-
vec!["*".to_string()]
8-
}
9-
106
pub fn is_true(value: &bool) -> bool {
117
*value
128
}
139

14-
pub fn is_false(value: &bool) -> bool {
15-
!*value
16-
}
17-
18-
pub fn is_empty<T>(value: &[T]) -> bool {
19-
value.is_empty()
10+
pub fn is_default<T: Default + PartialEq>(value: &T) -> bool {
11+
value == &T::default()
2012
}

0 commit comments

Comments
 (0)