Skip to content

Commit

Permalink
Reparse points and folder exclusions (#22)
Browse files Browse the repository at this point in the history
* Update ReadMe with support and contribution details. (#6)

Co-authored-by: Madushan <[email protected]>

* Fix to detect dependencies on .NET Framework projects.

* Adds support to show COM/DLL references. Feature #9

* Add support for custom titles in HTML output (#13)

* Added `-HtmlTitle` (`-HT`) option to specify a title for HTML output. Feature #11
* Updated README.md to reflect the new changes

* bump version number fr release

* Move to dotnet 6 LTS

* update build pipeline to use .NET 6 SDK

* use .NET 6 SDK for pipeline

* Support VB.NET Projects (#16)

vbproj files have the same format as csproj files and so can
also be used to gain information about referenced projects and
packages.

* read me update and version bump

* reparse point detection, folder exclusion, docs update, warnings in stderr.

Co-authored-by: Madushan <[email protected]>
Co-authored-by: Murray <[email protected]>
Co-authored-by: Philipp Grathwohl <[email protected]>
  • Loading branch information
4 people authored Jun 18, 2022
1 parent 7f5914e commit 44d9073
Show file tree
Hide file tree
Showing 7 changed files with 311 additions and 178 deletions.
2 changes: 1 addition & 1 deletion DependenSee/DependenSee.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<PackAsTool>true</PackAsTool>
<ToolCommandName>DependenSee</ToolCommandName>
<PackageOutputPath>./bin/nupkg</PackageOutputPath>
<Version>2.1.0</Version>
<Version>2.2.0</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
19 changes: 16 additions & 3 deletions DependenSee/PowerArgsProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ public enum OutputTypes
[ArgExceptionBehavior(ArgExceptionPolicy.StandardExceptionHandling)]
[ArgDescription(@"
==================================================================
| |
| For full documentation, support and reporting bugs |
Expand Down Expand Up @@ -43,10 +42,10 @@ public class PowerArgsProgram
public bool IncludePackages { get; set; }

[ArgDefaultValue(OutputTypes.Html)]
[ArgDescription("Type of the output.")]
[ArgDescription("Type of the output. Warnings are written to stderr. If you're piping the stdout, you may also want to check the stderr.")]
[ArgShortcut("T")]
public OutputTypes OutputType { get; set; }

[ArgDefaultValue("DependenSee")]
[ArgDescription("Document title for Html output. Ignored for other output types.")]
[ArgShortcut("HT")]
Expand All @@ -69,6 +68,16 @@ public class PowerArgsProgram
[ArgDescription("Comma separated list of package name prefixes to exclude. Wildcards not allowed. Only the filename is considered, case insensitive. If specified, 'IncludePackages' is overridden to True. This must be a subset of includes to be useful. Ex: 'Microsoft.Logging, Azure' Excludes packages starting with Microsoft.Logging and packages starting with Azure")]
[ArgShortcut("EPaN")]
public string ExcludePackageNamespaces { get; set; }
[ArgDefaultValue("")]
[ArgDescription("Comma Separated list of folders (either absolute paths or relative to SourceFolder) to skip during scan, even if there are references to them from your projects.")]
[ArgShortcut("EFol")]
public string ExcludeFolders { get; set; }

[ArgDefaultValue(false)]
[ArgDescription("Set if you want the scan to follow valid reparse points. This is helpful if your project references are relying on symlinks, NTFS junction points .etc.")]
[ArgShortcut("FReP")]
public bool FollowReparsePoints { get; set; }


public void Main()
{
Expand All @@ -81,10 +90,14 @@ public void Main()

IncludePackages = IncludePackages,

ExcludeFolders = ExcludeFolders,
FollowReparsePoints = FollowReparsePoints,

OutputPath = OutputPath,
OutputType = OutputType,

SourceFolder = SourceFolder,

};
var result = service.Discover();
new ResultWriter().Write(result, OutputType, OutputPath, HtmlTitle);
Expand Down
2 changes: 1 addition & 1 deletion DependenSee/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ private static void WriteUnexpectedException(Exception ex)
| - dotnet tool update DependenSee --global |
| |
| - check current version with |
| - dotnet tool update DependenSee --global |
| - dotnet tool list --global |
| |
| - Please open an issue at |
| - https://www.github.com/madushans/DependenSee |
Expand Down
41 changes: 41 additions & 0 deletions DependenSee/ReferenceDiscoveryService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public class ReferenceDiscoveryService
public string ExcludeProjectNamespaces { get; set; }
public string IncludePackageNamespaces { get; set; }
public string ExcludePackageNamespaces { get; set; }
public bool FollowReparsePoints { get; set; }
public string ExcludeFolders { get; set; }

private string[] _includeProjectNamespaces { get; set; }
private string[] _excludeProjectNamespaces { get; set; }
Expand Down Expand Up @@ -52,6 +54,26 @@ private static string[] ParseStringToLowercaseStringArray(string list) =>

private void Discover(string folder, DiscoveryResult result)
{
var info = new DirectoryInfo(folder);

var excludedByRule = GetFolderExclusionFor(info.FullName);
if (excludedByRule != null)
{
Console.Error.WriteLine($"Skipping folder '{folder}' excluded by rule '{excludedByRule}'\r\n\r\n");
return;
}

if (!info.Exists)
{
Console.Error.WriteLine($"Skipping scan for missing folder '{folder}'\r\n\r\n");
return;
}
if (info.Attributes.HasFlag(FileAttributes.ReparsePoint) && !FollowReparsePoints)
{
Console.Error.WriteLine($"Skipping scan for reparse point '{folder}'. Set {nameof(PowerArgsProgram.FollowReparsePoints)} flag to follow.\r\n\r\n");
return;
}

var projectFiles = Directory.EnumerateFiles(folder, "*.csproj")
.Concat(Directory.EnumerateFiles(folder, "*.vbproj"));
foreach (var file in projectFiles)
Expand Down Expand Up @@ -150,6 +172,20 @@ private List<Package> DiscoverPackageReferences(XmlDocument xml)
return packages;
}

private string GetFolderExclusionFor(string fullFolderPath)
{
if (string.IsNullOrWhiteSpace(ExcludeFolders)) return null;

var allRules = ExcludeFolders
.Split(',')
.Select(r => Path.IsPathRooted(r) ? r : Path.GetFullPath(r, SourceFolder))
.Select(r => r.ToLower().Trim())
.ToList();

fullFolderPath = fullFolderPath.ToLower();
return allRules.FirstOrDefault(r => fullFolderPath.StartsWith(r));
}

private List<Project> DiscoverProjectRefrences(XmlDocument xml, string basePath)
{
var projectReferenceNodes = xml.SelectNodes("//*[local-name() = 'ProjectReference']");
Expand All @@ -162,6 +198,11 @@ private List<Project> DiscoverProjectRefrences(XmlDocument xml, string basePath)

string filename = Path.GetFileNameWithoutExtension(fullPath);

if (!fullPath.ToLower().StartsWith(SourceFolder.ToLower()))
{
Console.Error.WriteLine($"Found referenced project '{fullPath}' outside of provided source folder. Run DependenSee on the parent folder of all your projects to prevent duplicates and/or missing projects from the output.\r\n\r\n");
}

projects.Add(new Project
{
Id = fullPath.Replace(SourceFolder, ""),
Expand Down
182 changes: 9 additions & 173 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ available on [Nuget](https://www.nuget.org/packages/DependenSee)

![Nuget Badge](https://buildstats.info/nuget/dependensee)

# Uninstall
## Uninstall
`dotnet tool uninstall DependenSee --global`

# How to Run
# Basic Usage

`DependenSee root/of/projects path/to/output.html`

See [full documentation](#Documentation)
See [full CLI documentation](/docs/CommandLine.md)

## Sample Output (HTML, interactive)

Expand All @@ -27,6 +27,11 @@ Download [this](https://raw.githubusercontent.com/madushans/DependenSee/main/sam
![DependenSee sample html output](https://raw.githubusercontent.com/madushans/DependenSee/main/sample-output.png)


# [Command Line Arguments > 🔗](/docs/CommandLine.md)

# [Troubleshooting > 🔗](/docs/Troubleshooting.md)


# Why `DependenSee` over 'X'

Current popular options are to either use NDepend, VS Architecture Explorer or Code Map. While these options are feature rich, they also has a licensing cost. If all you want is to see the dependency graph, and nothing else, it may be hard to justify the licensing cost. Then `DependenSee` is for you.
Expand All @@ -39,180 +44,11 @@ If you need to see the Type structure, relationships between your methods or typ
- Can only include or exclude certain namespaces so the result is not overwhelming or filled with noise.
- Can create HTML, XML, JSON and Graphviz outputs
- Can return output to `STDOUT` for further processing by other command line tools
- Returns errors and warnings to `STDERR`

For full docs run without any arguments
`DependenSee`

# Documentation

`Usage - DependenSee <SourceFolder> [<OutputPath>] -options`

## Help

Shows help descriptions. Help is also displayed if no arguments were provided.

**Shorthand: `-H`**

### Examples
- `DependenSee -Help`
- `DependenSee -H`
- `DependenSee`

## SourceFolder [Required]

Root folder (usually solution folder) to look for csproj files recursively. If no explicit options are specified, the first argument is assumed to be this option.

If your path has spaces, you will need to enclose it in double quotes.

### Examples

- `DependenSee \Source\MySolutionFolder`
- `DependenSee -SourceFolder \Source\MySolutionFolder`
- `DependenSee -S \Source\MySolutionFolder`

## OutputPath

Path to write the result. Not required if writing the output to stdout.
If no explicit options are specified, the second argument is assumed to be this option.

If your path has spaces, you will need to enclose it in double quotes.

**Shorthand: `-O`**

### Examples

- `DependenSee \Source\SolutionFolder \Test\MyOutput.html`
- `DependenSee \Source\SolutionFolder -O \Test\MyOutput.html`
- `DependenSee \Source\SolutionFolder -OutputPath \Test\MyOutput.html`

## IncludePackages

Whether to include external (Nuget) packages in the result.

**Shorthand: `-P`**

**Default: `False`**


### Examples

- `DependenSee \Source\SolutionFolder \Test\MyOutput.html -P`
- `DependenSee \Source\SolutionFolder \Test\MyOutput.html -IncludePackages`

## OutputType

Type of output to produce. Following types are available.

- `Html` - Creates an html document.
- `Json` - Creates a JSON file.
- `Xml` - Creates a XML file.
- `Graphviz` - Creates a Graphviz/DOT file.
- `ConsoleJson` - Writes JSON output to stdout
- `ConsoleXml` - Writes XML output to stdout
- `GonsoleGraphviz` - Writes Graphviz output to stdout

When a `Console...` type output is specified, the `-OutputPath` can be ommitted.

To visualize Graphviz output, either use
- Use an online visualizer such as [https://dreampuf.github.io/GraphvizOnline](https://dreampuf.github.io/GraphvizOnline)

- or use tooling from [https://graphviz.org](https://graphviz.org)
- once installed you can use `.\dot.exe DependenSee-OutputFile.dot -oTargetFile.Svg -Tsvg`
- `dot.exe` is located at `your-graphvis-installation/bin`
- see Graphviz docs for [command line usage](https://graphviz.org/doc/info/command.html) and supported [output types](https://graphviz.org/doc/info/output.html)

**Shorthand: `-T`**

**Default: `Html`**

### Examples

- `DependenSee \Source\SolutionFolder \Test\MyOutput.html -T Xml`
- `DependenSee \Source\SolutionFolder \Test\MyOutput.html -OutputType Json`
- `DependenSee \Source\SolutionFolder -T ConsoleJson`

## HtmlTitle

Document title for Html output. Ignored when creating output types other than `Html`.

If your title has spaces, you will need to enclose it in double quotes. The title should not be HTML-encoded ahead of time as DependenSee will do this automatically.

**Shorthand: `-HT`**

**Default: `DependenSee`**

### Examples

- `DependenSee \Source\SolutionFolder \Test\MyOutput.html -HtmlTitle "My Graph Title"`
- `DependenSee \Source\SolutionFolder \Test\MyOutput.html -T Html -HtmlTitle my-graph-title`
- `DependenSee \Source\SolutionFolder \Test\MyOutput.html -HT "My Graph Title"`

## IncludeProjectNamespaces
Comma separated list of project file prefixes to include. Wildcards not allowed. Only the filename is considered, case insensitive.

If you want to include spaces between items, make sure you enclose the parameter value in double quotes.

**Shorthand: `-IPrN`**

**Default: `<empty string>`**

### Examples

- `DependenSee \Source\SolutionFolder -O ConsoleJson -IncludeProjectNamespaces MyApp.Extensions,MyApp.Core`
- Includes only projects starting with MyApp.Core and projects starting with MyApp.Extensions
- `DependenSee \Source\SolutionFolder -O ConsoleJson -IPrN MyApp.Extensions,MyApp.Core`
- Includes only projects starting with MyApp.Core and projects starting with MyApp.Extensions

## ExcludeProjectNamespaces

Comma separated list of project file prefixes to exclude. Wildcards not allowed. Only the filename is considered, case insensitive. This must be a subset of includes to be useful.

If you want to include spaces between items, make sure you enclose the parameter value in double quotes.

**Shorthand: `-EPrN`**

**Default: `<unspecified>`**

### Examples

- `DependenSee \Source\SolutionFolder -O ConsoleJson -ExcludeProjectNamespaces MyApp.Extensions, MyApp.Helpers`
- Excludes projects starting with MyApp.Extensions and projects starting with MyApp.Helpers
- `DependenSee \Source\SolutionFolder -O ConsoleJson -EPrN MyApp.Extensions, MyApp.Helpers`
- Excludes projects starting with MyApp.Extensions and projects starting with MyApp.Helpers

## IncludePackageNamespaces
Comma separated list of package name prefixes to include. Wildcards not allowed. Only the package name is considered, case insensitive. If specified, `-IncludePackages` is overridden to `True`.

If you want to include spaces between items, make sure you enclose the parameter value in double quotes.

**Shorthand: `-IPaN`**

**Default: `<empty string>`**

### Examples

- `DependenSee \Source\SolutionFolder -O ConsoleJson -IncludePackageNamespaces Xamarin,Microsoft`
- includes **only** packages starting with Xamarin and packages starting with Microsoft
- `DependenSee \Source\SolutionFolder -O ConsoleJson -IPaN Xamarin,Microsoft`
- includes **only** packages starting with Xamarin and packages starting with Microsoft

## ExcludePackageNamespaces

Comma separated list of package name prefixes to exclude. Wildcards not allowed. Only the filename is considered, case insensitive. If specified, `-IncludePackages` is overridden to `True`. This must be a subset of includes to be useful.

If you want to include spaces between items, make sure you enclose the parameter value in double quotes.

**Shorthand: `-EPaN`**

**Default: `<unspecified>`**

### Examples

- `DependenSee \Source\SolutionFolder -O ConsoleJson -ExcludePackageNamespaces Microsoft.Logging,Azure`
- Excludes packages starting with `Microsoft.Logging` and packages starting with `Azure`
- `DependenSee \Source\SolutionFolder -O ConsoleJson -EPaN Microsoft.Logging,Azure`
- Excludes packages starting with `Microsoft.Logging` and packages starting with `Azure`


# Privacy and Security Note

Expand Down
Loading

0 comments on commit 44d9073

Please sign in to comment.