<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>http://wiki.integrics.com/index.php?action=history&amp;feed=atom&amp;title=Cyclic_dependencies_in_Enswitch_Perl_backend</id>
	<title>Cyclic dependencies in Enswitch Perl backend - Revision history</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.integrics.com/index.php?action=history&amp;feed=atom&amp;title=Cyclic_dependencies_in_Enswitch_Perl_backend"/>
	<link rel="alternate" type="text/html" href="http://wiki.integrics.com/index.php?title=Cyclic_dependencies_in_Enswitch_Perl_backend&amp;action=history"/>
	<updated>2026-05-06T23:27:45Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.31.7</generator>
	<entry>
		<id>http://wiki.integrics.com/index.php?title=Cyclic_dependencies_in_Enswitch_Perl_backend&amp;diff=368&amp;oldid=prev</id>
		<title>Rodolfojcj: A way to identify cyclic dependencies in Perl modules of Enswitch</title>
		<link rel="alternate" type="text/html" href="http://wiki.integrics.com/index.php?title=Cyclic_dependencies_in_Enswitch_Perl_backend&amp;diff=368&amp;oldid=prev"/>
		<updated>2024-03-24T06:14:26Z</updated>

		<summary type="html">&lt;p&gt;A way to identify cyclic dependencies in Perl modules of Enswitch&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Given that cyclic dependencies between modules may bring runtime errors, the following is recommended:&lt;br /&gt;
&lt;br /&gt;
* Identify where they happen.&lt;br /&gt;
* Refactor the source code to break them.&lt;br /&gt;
&lt;br /&gt;
The details in this page are related with the first point, specifically with the Perl based Enswitch backend.&lt;br /&gt;
&lt;br /&gt;
== Automatically finding them ==&lt;br /&gt;
&lt;br /&gt;
* Use a machine where a copy of the Enswitch source code exists and take note of its directory path, for example:&lt;br /&gt;
** /opt/enswitch&lt;br /&gt;
** /opt/enswitch/4.3&lt;br /&gt;
** /home/user/copy_of_enswitch_4.2&lt;br /&gt;
&lt;br /&gt;
* Install the packages that will be needed. For Debian or Ubuntu, run these commands:&lt;br /&gt;
&lt;br /&gt;
  cpanm App::PrereqGrapher&lt;br /&gt;
  apt-get install graphviz&lt;br /&gt;
  apt-get install python3-networkx python3-graphviz python3-pydot python3-pydotplus python-is-python3&lt;br /&gt;
&lt;br /&gt;
* Save the following contents to a file (e.g ''/tmp/enswitch-cyclic-dependencies-finder.pl''), which analyses the files inside the ''bin'' and ''lib'' subdirectories of Enswitch, assuming by default that they are under the ''/opt/enswitch'' directory.&lt;br /&gt;
&lt;br /&gt;
  use App::PrereqGrapher;&lt;br /&gt;
  use Getopt::Long;&lt;br /&gt;
  use Module::Metadata;&lt;br /&gt;
  use strict;&lt;br /&gt;
  use warnings;&lt;br /&gt;
  &lt;br /&gt;
  my $source_dir = '/opt/enswitch';&lt;br /&gt;
  my $out_dir;&lt;br /&gt;
  my $depth = 2;&lt;br /&gt;
  &lt;br /&gt;
  GetOptions( 'source-dir=s' =&amp;gt; \$source_dir, 'out-dir=s' =&amp;gt; \$out_dir, 'depth:i' =&amp;gt; \$depth, );&lt;br /&gt;
  &lt;br /&gt;
  $source_dir =~ s|/$||;&lt;br /&gt;
  $out_dir or die &amp;quot;Output directory is required.\n&amp;quot;;&lt;br /&gt;
  $out_dir =~ s|/$||;&lt;br /&gt;
  &lt;br /&gt;
  for my $d ( 'bin', 'lib' ) {&lt;br /&gt;
          opendir( DIR, $source_dir . &amp;quot;/&amp;quot; . $d ) or die &amp;quot;Could not open $d\n&amp;quot;;&lt;br /&gt;
          while ( my $f = readdir( DIR ) ) {&lt;br /&gt;
                  my $info = Module::Metadata-&amp;gt;new_from_file( &amp;quot;$source_dir/$d/$f&amp;quot; );&lt;br /&gt;
                  if ( $info-&amp;gt;{ 'module' } &amp;amp;&amp;amp; $info-&amp;gt;{ 'module' } ne 'main' )  {&lt;br /&gt;
                          print &amp;quot;$source_dir/$d/$f =&amp;gt; &amp;quot; . $info-&amp;gt;{ 'module' } . &amp;quot;\n&amp;quot;;&lt;br /&gt;
                          generate_dot_file( $info-&amp;gt;{ 'module' } );&lt;br /&gt;
                          transform_dot_file( $info-&amp;gt;{ 'module' }, 'pdf' );&lt;br /&gt;
                          transform_dot_file( $info-&amp;gt;{ 'module' }, 'svg' );&lt;br /&gt;
                          find_dependencies_cycles( $info-&amp;gt;{ 'module' } );&lt;br /&gt;
                  }&lt;br /&gt;
          }&lt;br /&gt;
          filter_bidirectional_dependencies_cycles();&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  sub generate_dot_file {&lt;br /&gt;
          my $module = shift;&lt;br /&gt;
          my %options = (&lt;br /&gt;
                  format =&amp;gt; 'dot',&lt;br /&gt;
                  no_core =&amp;gt; 1,&lt;br /&gt;
                  no_recurse_core =&amp;gt; 1,&lt;br /&gt;
                  depth =&amp;gt; $depth,&lt;br /&gt;
                  output_file =&amp;gt; $out_dir . &amp;quot;/&amp;quot; . $module =~ s/::/_/gr . &amp;quot;.dot&amp;quot;,&lt;br /&gt;
                  verbose =&amp;gt; 0,&lt;br /&gt;
          );&lt;br /&gt;
          my $grapher = App::PrereqGrapher-&amp;gt;new( %options );&lt;br /&gt;
          $grapher-&amp;gt;generate_graph( $module );&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  sub transform_dot_file {&lt;br /&gt;
          my $module = shift;&lt;br /&gt;
          my $format = shift;&lt;br /&gt;
          my $dot_file = $out_dir . &amp;quot;/&amp;quot; . $module =~ s/::/_/gr . &amp;quot;.dot&amp;quot;;&lt;br /&gt;
          print &amp;quot;Converting $dot_file to $format.\n&amp;quot;;&lt;br /&gt;
          system( &amp;quot;dot -T$format -O $dot_file&amp;quot; );&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  sub find_dependencies_cycles {&lt;br /&gt;
          my $module = shift;&lt;br /&gt;
          my $finder_path = '/tmp/dot_find_cycles.py';&lt;br /&gt;
          if ( ! -f $finder_path ) {&lt;br /&gt;
                  system( &amp;quot;wget --output-document=$finder_path https://github.com/jantman/misc-scripts/raw/master/dot_find_cycles.py&amp;quot; );&lt;br /&gt;
                  system( &amp;quot;chmod +x $finder_path&amp;quot; );&lt;br /&gt;
          }&lt;br /&gt;
          my $dot_file = $out_dir . &amp;quot;/&amp;quot; . $module =~ s/::/_/gr . &amp;quot;.dot&amp;quot;;&lt;br /&gt;
          my $txt_file = $out_dir . &amp;quot;/&amp;quot; . $module =~ s/::/_/gr . &amp;quot;.cycles.txt&amp;quot;;&lt;br /&gt;
          print &amp;quot;Finding dependencies cycles in $dot_file.\n&amp;quot;;&lt;br /&gt;
          system( &amp;quot;$finder_path $dot_file &amp;gt; $txt_file&amp;quot; );&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  sub filter_bidirectional_dependencies_cycles {&lt;br /&gt;
          my $txts = $out_dir . &amp;quot;/&amp;quot; . &amp;quot;*.cycles.txt&amp;quot;;&lt;br /&gt;
          my $filtered_file = $out_dir . &amp;quot;/&amp;quot; . &amp;quot;bidirectional.cycles.txt&amp;quot;;&lt;br /&gt;
          print &amp;quot;Filtering bi-directional dependencies cycles in file patterns $txts.\n&amp;quot;;&lt;br /&gt;
          system( &amp;quot;cat $txts | sort | uniq | &amp;quot; . 'egrep &amp;quot;^(.+) -&amp;gt; ([^-&amp;gt;]+) -&amp;gt; \1$&amp;quot;' . &amp;quot; &amp;gt; $filtered_file&amp;quot; );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
* Create a directory to store the results, for example ''/tmp/enswitch-cyclic-dependencies-results''.&lt;br /&gt;
&lt;br /&gt;
* Run the previously saved script like this:&lt;br /&gt;
&lt;br /&gt;
  perl /tmp/enswitch-cyclic-dependencies-finder.pl --out-dir=/tmp/enswitch-cyclic-dependencies-results --source-dir=/home/myuser/enswitch_4.4_copy&lt;br /&gt;
&lt;br /&gt;
* The results include these:&lt;br /&gt;
** [https://en.wikipedia.org/wiki/DOT_%28graph_description_language%29 DOT files] for the found Enswitch packages.&lt;br /&gt;
** PDF and SVG files for visual representations of those DOT files.&lt;br /&gt;
** Text files listing the found cyclic dependencies.&lt;br /&gt;
** A text file named ''bidirectional.cycles.txt'' that lists the cyclic dependencies more likely to raise runtime errors and that are recommended to be refactored.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* https://blogs.perl.org/users/neilb/2012/12/prereq-grapher.html&lt;br /&gt;
* https://metacpan.org/pod/App::PrereqGrapher&lt;br /&gt;
* https://coderwall.com/p/5ri4dw/resolve-circular-dependencies-with-carp-always&lt;br /&gt;
* https://metacpan.org/pod/circular::require&lt;br /&gt;
* https://blog.jasonantman.com/2012/03/python-script-to-find-dependency-cycles-in-graphviz-dot-files/&lt;br /&gt;
* https://github.com/jantman/misc-scripts/blob/master/dot_find_cycles.py&lt;/div&gt;</summary>
		<author><name>Rodolfojcj</name></author>
		
	</entry>
</feed>