Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import std.stdio;
- import std.string;
- import std.process;
- import std.json;
- import std.path;
- import std.range;
- import std.file;
- int main(string[] args)
- {
- try
- {
- Project project = parseDubDescription();
- Metrics m = project.getMetrics();
- writeln;
- writefln("Total packages: %s", m.numPackages);
- writefln("Total source files: %s", m.numSourceFiles);
- writefln("Total LOC (non-empty): %s", m.numNonEmptyLines);
- // Print LOC and files per packages
- writeln;
- writeln("Per-package metrics:");
- foreach(pack; project.packages)
- {
- Metrics pm = pack.getMetrics();
- writefln(" - %s: %s lines in %s source files", pack.name, pm.numNonEmptyLines, pm.numSourceFiles);
- }
- writeln;
- return 0;
- }
- catch(Exception e)
- {
- writeln(e.msg);
- return 1;
- }
- }
- class Project
- {
- Package[] packages;
- Metrics getMetrics()
- {
- Metrics res;
- foreach(pack; packages)
- {
- res = res + pack.getMetrics();
- }
- return res;
- }
- }
- class Package
- {
- string name;
- SourceFile[] sourceFiles;
- this(string name)
- {
- this.name = name;
- }
- Metrics getMetrics()
- {
- Metrics res;
- foreach(source; sourceFiles)
- {
- res = res + source.getMetrics();
- }
- res.numPackages = 1;
- return res;
- }
- }
- class SourceFile
- {
- string path;
- this(string path)
- {
- this.path = path;
- _metrics = computeFileMetrics(path);
- _metrics.numSourceFiles = 1;
- }
- Metrics getMetrics()
- {
- return _metrics;
- }
- private:
- Metrics _metrics;
- }
- Project parseDubDescription()
- {
- Project project = new Project;
- auto dubResult = execute(["dub", "describe"]);
- if (dubResult.status != 0)
- throw new Exception(format("dub returned %s", dubResult.status));
- JSONValue description = parseJSON(dubResult.output);
- foreach (pack; description["packages"].array())
- {
- string absPath = pack["path"].str;
- string packName = pack["name"].str;
- Package p = new Package(packName);
- foreach (file; pack["files"].array())
- {
- string filepath = file["path"].str();
- // only add .d files
- if (filepath.endsWith(".d") || filepath.endsWith(".di") || filepath.endsWith(".json") || filepath.endsWith(".res"))
- {
- p.sourceFiles ~= new SourceFile( buildPath(absPath, filepath) );
- }
- }
- project.packages ~= p;
- }
- return project;
- }
- struct Metrics
- {
- size_t numNonEmptyLines = 0;
- size_t numLines = 0;
- size_t numBytes = 0;
- size_t numSourceFiles = 0;
- size_t numPackages = 0;
- Metrics opBinary(string op)(Metrics other) if (op == "+")
- {
- Metrics result;
- result.numNonEmptyLines = numNonEmptyLines + other.numNonEmptyLines;
- result.numLines = numLines + other.numLines;
- result.numBytes = numBytes + other.numBytes;
- result.numSourceFiles = numSourceFiles + other.numSourceFiles;
- result.numPackages = numPackages + other.numPackages;
- return result;
- }
- }
- Metrics computeFileMetrics(string absPath)
- {
- const(char)[] content = cast(const(char)[]) std.file.read(absPath);
- Metrics m;
- m.numBytes = content.length;
- m.numSourceFiles = 0;
- m.numPackages = 0;
- enum State
- {
- IN_LINE,
- SEEN_CR
- }
- int lineLength = 0;
- State state = State.IN_LINE;
- void newLine()
- {
- if (lineLength != 0) // not empty line
- m.numNonEmptyLines += 1;
- m.numLines += 1;
- lineLength = 0;
- }
- foreach(ch; content)
- {
- final switch(state) with (State)
- {
- case IN_LINE:
- if (ch == '\n')
- {
- newLine();
- // proceed to new line
- }
- else if (ch == '\r')
- {
- state = SEEN_CR;
- }
- else
- lineLength += 1;
- break;
- case SEEN_CR:
- if (ch == '\n') // \r\n => one line
- {
- newLine();
- state = IN_LINE;
- // proceed to new line
- }
- else if (ch == '\r') // \r\r => one line
- {
- newLine(); // and stay here
- state = SEEN_CR;
- }
- else // was stand-alone \r => one line
- {
- newLine();
- lineLength += 1;
- }
- break;
- }
- }
- return m;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement