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

Avoid cyclic dependencies between modules #1400

Closed
Elv13 opened this issue Jan 15, 2017 · 8 comments
Closed

Avoid cyclic dependencies between modules #1400

Elv13 opened this issue Jan 15, 2017 · 8 comments
Assignees
Labels

Comments

@Elv13
Copy link
Member

Elv13 commented Jan 15, 2017

gears.color->beautiful.init->beautiful.theme_assets->gears.color = BOOM

How this got past the CI...

Simplest solution, don't require theme_assets in beautiful.init

@Elv13
Copy link
Member Author

Elv13 commented Jan 15, 2017

nevermind, it can't happen on master. /me have too many patches

@Elv13 Elv13 closed this as completed Jan 15, 2017
@psychon
Copy link
Member

psychon commented Jan 17, 2017

Should we define some hard rules on what might depend on what to make sure we have no cyclic dependencies? For example, I would propose that gears must not use beautiful...

@Elv13
Copy link
Member Author

Elv13 commented Jan 18, 2017

Sure. It will however require some changes as gears depends on awful.util.

gears: depends on nothing
wibox: depends on gears
beautiful: depends on gears
awful: depends on everything

awful.util deprecation support can be moved into gears.deprecation. awful.util.table should be moved to table itself. awful.util string utils should move into string. This can be done without breaking the API (with aliases).

@actionless
Copy link
Member

why not to move awful.util to just util?

@psychon
Copy link
Member

psychon commented Jan 19, 2017

I don't think we should start monkey-patching standard Lua things. We already do that too much. That leads to too much confusion. Also 'util' is too much of a generic name that eventually some name collision will occur.
Edit: Besides that: 👍

@psychon psychon changed the title Cyclic dependency in theme_assets Avoid cyclic dependencies between modules Jan 19, 2017
@psychon psychon assigned psychon and unassigned actionless Jan 19, 2017
@psychon
Copy link
Member

psychon commented Jan 19, 2017

(My plan is to implement a tool that tries to automatically check the above rules and complains if they are not followed.)
Edit: Even better: https://github.com/mpeterv/depgraph
Edit:
t dot

@psychon
Copy link
Member

psychon commented Jan 21, 2017

Following program run in the awesome source directory:

local depgraph = require("depgraph")

local allowed_deps = {
	gears = {
		lgi = true,
	},
	beautiful = {
		gears = true,
		lgi = true,
	},
	wibox = {
		beautiful = true,
		gears = true,
		lgi = true,
	},
	awful = {
		beautiful = true,
		gears = true,
		lgi = true,
		wibox = true,
	},
	naughty = {
		awful = true,
		beautiful = true,
		gears = true,
		lgi = true,
		wibox = true,
	},
	menubar = {
		awful = true,
		beautiful = true,
		gears = true,
		lgi = true,
		wibox = true,
	}
}

local graph = assert(depgraph.make_graph({"lib"}, {}, "lib", nil, nil))

for _, module in ipairs(graph.modules) do
	local base_name = string.match(module.name, "%a*")
	local allowed = allowed_deps[base_name] or {}
	for _, dep in ipairs(module.deps) do
		local dep_base_name = string.match(dep.name, "%a*")
		if base_name ~= dep_base_name and not allowed[dep_base_name] then
			print(string.format("Unallowed dependency by %s to %s (%s -> %s)",
					module.name, dep.name, base_name, dep_base_name))
		end
	end
end

produces the following output:

Unallowed dependency by awful.hotkeys_popup.widget to menubar (awful -> menubar)
Unallowed dependency by beautiful.xresources to awful.util (beautiful -> awful)
Unallowed dependency by gears.object to awful.util (gears -> awful)
Unallowed dependency by gears.surface to wibox.hierarchy (gears -> wibox)
Unallowed dependency by wibox.container.arcchart to awful.util (wibox -> awful)
Unallowed dependency by wibox.container.background to awful.util (wibox -> awful)
Unallowed dependency by wibox.container.constraint to awful.util (wibox -> awful)
Unallowed dependency by wibox.container.margin to awful.util (wibox -> awful)
Unallowed dependency by wibox.container.mirror to awful.util (wibox -> awful)
Unallowed dependency by wibox.container.radialprogressbar to awful.util (wibox -> awful)
Unallowed dependency by wibox.container.rotate to awful.util (wibox -> awful)
Unallowed dependency by wibox.layout.align to awful.util (wibox -> awful)
Unallowed dependency by wibox.layout.constraint to awful.util (wibox -> awful)
Unallowed dependency by wibox.layout.fixed to awful.util (wibox -> awful)
Unallowed dependency by wibox.layout.flex to awful.util (wibox -> awful)
Unallowed dependency by wibox.layout.margin to awful.util (wibox -> awful)
Unallowed dependency by wibox.layout.mirror to awful.util (wibox -> awful)
Unallowed dependency by wibox.layout.ratio to awful.util (wibox -> awful)
Unallowed dependency by wibox.layout.rotate to awful.util (wibox -> awful)
Unallowed dependency by wibox.layout.scroll to awful.util (wibox -> awful)
Unallowed dependency by wibox.layout.stack to awful.util (wibox -> awful)
Unallowed dependency by wibox.widget.background to awful.util (wibox -> awful)
Unallowed dependency by wibox.widget.base to awful.util (wibox -> awful)
Unallowed dependency by wibox.widget.checkbox to awful.util (wibox -> awful)
Unallowed dependency by wibox.widget.imagebox to awful.util (wibox -> awful)
Unallowed dependency by wibox.widget.piechart to awful.util (wibox -> awful)
Unallowed dependency by wibox.widget.progressbar to awful.util (wibox -> awful)
Unallowed dependency by wibox.widget.slider to awful.util (wibox -> awful)
Unallowed dependency by wibox.widget.systray to awful.util (wibox -> awful)
Unallowed dependency by wibox.widget.textbox to awful.util (wibox -> awful)

So... how do we get from here to a situation that does not violate the proposed rules?

@psychon
Copy link
Member

psychon commented Jan 21, 2017

Also: We might want to run luadepgraph -m lib -p lib --cycles --strict during a normal build to check for cyclic strong dependencies.

psychon added a commit to psychon/awesome that referenced this issue Feb 8, 2017
Currently, "everything can require everything". It's an unstructured
mess which sometimes causes problems.

This commit adds a tool that enforces a white-list of require() uses. It
uses depgraph to scan the source code and then each use of require()
that is found is checked. If any violations are found, the tool returns
a failure.

This tool is wired up to a new target "make check-requires" which is
included in "make check". Thus, Travis will run this.

Reference: awesomeWM#1400
Signed-off-by: Uli Schlachter <psychon@znc.in>
@psychon psychon closed this as completed Feb 8, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants