Advertisement
Guest User

dloc: extract package and significant LOC from your D projects

a guest
Jun 28th, 2022
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 4.94 KB | None | 0 0
  1. import std.stdio;
  2. import std.string;
  3. import std.process;
  4. import std.json;
  5. import std.path;
  6. import std.range;
  7. import std.file;
  8.  
  9. int main(string[] args)
  10. {
  11.     try
  12.     {
  13.  
  14.         Project project = parseDubDescription();
  15.  
  16.         Metrics m = project.getMetrics();
  17.  
  18.         writeln;
  19.         writefln("Total packages:        %s", m.numPackages);
  20.         writefln("Total source files:    %s", m.numSourceFiles);
  21.         writefln("Total LOC (non-empty): %s", m.numNonEmptyLines);
  22.  
  23.  
  24.         // Print LOC and files per packages
  25.         writeln;
  26.         writeln("Per-package metrics:");
  27.         foreach(pack; project.packages)
  28.         {
  29.             Metrics pm = pack.getMetrics();
  30.             writefln("  - %s: %s lines in %s source files", pack.name, pm.numNonEmptyLines, pm.numSourceFiles);
  31.         }
  32.         writeln;
  33.  
  34.         return 0;
  35.     }
  36.     catch(Exception e)
  37.     {
  38.         writeln(e.msg);
  39.         return 1;
  40.     }
  41. }
  42.  
  43. class Project
  44. {
  45.     Package[] packages;
  46.  
  47.     Metrics getMetrics()
  48.     {
  49.         Metrics res;
  50.         foreach(pack; packages)
  51.         {
  52.             res = res + pack.getMetrics();
  53.         }
  54.         return res;
  55.     }
  56. }
  57.  
  58. class Package
  59. {
  60.     string name;
  61.     SourceFile[] sourceFiles;
  62.  
  63.     this(string name)
  64.     {
  65.         this.name = name;
  66.     }
  67.  
  68.     Metrics getMetrics()
  69.     {
  70.         Metrics res;
  71.         foreach(source; sourceFiles)
  72.         {
  73.             res = res + source.getMetrics();
  74.         }
  75.         res.numPackages = 1;
  76.         return res;
  77.     }
  78. }
  79.  
  80. class SourceFile
  81. {
  82.     string path;
  83.  
  84.     this(string path)
  85.     {
  86.         this.path = path;      
  87.         _metrics = computeFileMetrics(path);
  88.         _metrics.numSourceFiles = 1;
  89.     }
  90.  
  91.     Metrics getMetrics()
  92.     {
  93.         return _metrics;
  94.     }
  95.  
  96. private:
  97.     Metrics _metrics;
  98. }
  99.  
  100.  
  101. Project parseDubDescription()
  102. {
  103.     Project project = new Project;
  104.  
  105.     auto dubResult = execute(["dub", "describe"]);
  106.  
  107.     if (dubResult.status != 0)
  108.         throw new Exception(format("dub returned %s", dubResult.status));
  109.  
  110.     JSONValue description = parseJSON(dubResult.output);
  111.  
  112.     foreach (pack; description["packages"].array())
  113.     {
  114.         string absPath = pack["path"].str;
  115.         string packName = pack["name"].str;
  116.  
  117.         Package p = new Package(packName);
  118.  
  119.         foreach (file; pack["files"].array())
  120.         {
  121.             string filepath = file["path"].str();
  122.  
  123.             // only add .d files
  124.             if (filepath.endsWith(".d") || filepath.endsWith(".di") || filepath.endsWith(".json") || filepath.endsWith(".res"))
  125.             {
  126.                 p.sourceFiles ~= new SourceFile( buildPath(absPath, filepath) );
  127.             }
  128.         }
  129.         project.packages ~= p;
  130.     }
  131.  
  132.     return project;
  133. }
  134.  
  135. struct Metrics
  136. {
  137.     size_t numNonEmptyLines = 0;
  138.     size_t numLines = 0;
  139.     size_t numBytes = 0;
  140.     size_t numSourceFiles = 0;
  141.     size_t numPackages = 0;
  142.  
  143.     Metrics opBinary(string op)(Metrics other) if (op == "+")
  144.     {
  145.         Metrics result;
  146.         result.numNonEmptyLines = numNonEmptyLines + other.numNonEmptyLines;
  147.         result.numLines = numLines + other.numLines;
  148.         result.numBytes = numBytes + other.numBytes;
  149.         result.numSourceFiles = numSourceFiles + other.numSourceFiles;
  150.         result.numPackages = numPackages + other.numPackages;
  151.         return result;
  152.     }
  153. }
  154.  
  155. Metrics computeFileMetrics(string absPath)
  156. {
  157.     const(char)[] content = cast(const(char)[]) std.file.read(absPath);
  158.  
  159.  
  160.     Metrics m;
  161.     m.numBytes = content.length;
  162.     m.numSourceFiles = 0;
  163.     m.numPackages = 0;
  164.  
  165.     enum State
  166.     {
  167.         IN_LINE,
  168.         SEEN_CR
  169.     }
  170.  
  171.     int lineLength = 0;
  172.  
  173.     State state = State.IN_LINE;
  174.  
  175.     void newLine()
  176.     {
  177.         if (lineLength != 0) // not empty line
  178.             m.numNonEmptyLines += 1;
  179.         m.numLines += 1;
  180.         lineLength = 0;
  181.     }
  182.  
  183.     foreach(ch; content)
  184.     {
  185.         final switch(state) with (State)
  186.         {
  187.             case IN_LINE:
  188.                 if (ch == '\n')
  189.                 {
  190.                     newLine();
  191.                     // proceed to new line
  192.                 }
  193.                 else if (ch == '\r')
  194.                 {
  195.                     state = SEEN_CR;
  196.                 }
  197.                 else
  198.                     lineLength += 1;
  199.                 break;
  200.  
  201.             case SEEN_CR:
  202.                 if (ch == '\n') // \r\n => one line
  203.                 {
  204.                     newLine();
  205.                     state = IN_LINE;
  206.                     // proceed to new line
  207.                 }
  208.                 else if (ch == '\r') // \r\r => one line
  209.                 {
  210.                     newLine(); // and stay here
  211.                     state = SEEN_CR;
  212.                 }
  213.                 else // was stand-alone \r => one line
  214.                 {
  215.                     newLine();
  216.                     lineLength += 1;
  217.                 }
  218.                 break;
  219.         }
  220.     }
  221.     return m;
  222. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement