Skip to content

Commit

Permalink
Improving device generation to support multilanguage pattern (nanofra…
Browse files Browse the repository at this point in the history
  • Loading branch information
Ellerbach authored Jan 22, 2023
1 parent 15b3afe commit 875dba8
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 69 deletions.
25 changes: 13 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
-----
Document Language: [English](README.md) | [简体中文](README.zh-cn.md)

## Welcome to the **nanoFramework** team code samples repository!
# Welcome to the **nanoFramework** team code samples repository!

This repo contains code samples used by the team when testing, working on proof of concepts for new and improved features and other explorational endeavours.
Feel free to browse, take what you like and contribute back if you want.
Expand Down Expand Up @@ -39,11 +39,12 @@ Our samples uses 🌶️ to show how easy or complicated those samples are. The
* [🌶️ - System.Device.PWM sample](samples/PWM)
* [🌶️ - System.Device.Spi sample](samples/SPI)
* [🌶️ to 🌶️🌶️ - System.IO.Ports serial Communication sample](samples/SerialCommunication)
* [🌶️🌶️ - I2C GPS sample](samples/I2C/System.Device.I2c/GPS)
* [🌶️🌶️ - I2C sample sample pack](samples/I2C)
* [🌶️🌶️ - I2C Scanner sample](samples/I2C/NanoI2cScanner)
* [🌶️🌶️ - I2S Microphone sample](samples/I2S/Input)
* [🌶️🌶️ - I2S sample pack](samples/I2S)
* [🌶️🌶️🌶️ - Using Azure SDK with BMP280 on M5Stack with .NET nanoFramework](samples/AzureSDK/AzureSDKSensorCertificate)
* [🌶️🌶️ - I2S Speaker sample](samples/I2S/Output)
* [🌶️🌶️🌶️ - Using Azure SDK with BMP280 on M5Stack with .NET nanoFramework](samples/AzureSDK/AzureSDKSensorCertificate/Readme.md)

### AMQP

Expand All @@ -65,7 +66,7 @@ Our samples uses 🌶️ to show how easy or complicated those samples are. The
* [🌶️🌶️🌶️ - Complete Azure MQTT sample using BMP280 sensor **without Azure lib** and with deep sleep](samples/AzureMQTTTwinsBMP280Sleep)
* [🌶️🌶️🌶️ - HTTP.HttpAzureGET Sample](samples/HTTP/HttpAzureGET)
* [🌶️🌶️🌶️ - HTTP.HttpAzurePOST Sample](samples/HTTP/HttpAzurePOST)
* [🌶️🌶️🌶️ - Using Azure SDK with BMP280 on M5Stack with .NET nanoFramework](samples/AzureSDK/AzureSDKSensorCertificate)
* [🌶️🌶️🌶️ - Using Azure SDK with BMP280 on M5Stack with .NET nanoFramework](samples/AzureSDK/AzureSDKSensorCertificate/Readme.md)
* [Azure IoT Device Provisioning Service (DPS) example](samples/AzureSDK/DpsSampleApp)

### Bluetooth
Expand Down Expand Up @@ -115,7 +116,7 @@ Our samples uses 🌶️ to show how easy or complicated those samples are. The

* [🌶️🌶️🌶️ - Complete Azure MQTT sample using BMP280 sensor **with** Azure lib and deep sleep](samples/AzureSDK/AzureSDKSleepBMP280)
* [🌶️🌶️🌶️ - Complete Azure MQTT sample using BMP280 sensor **without Azure lib** and with deep sleep](samples/AzureMQTTTwinsBMP280Sleep)
* [🌶️🌶️🌶️ - Using Azure SDK with BMP280 on M5Stack with .NET nanoFramework](samples/AzureSDK/AzureSDKSensorCertificate)
* [🌶️🌶️🌶️ - Using Azure SDK with BMP280 on M5Stack with .NET nanoFramework](samples/AzureSDK/AzureSDKSensorCertificate/Readme.md)

### Interop

Expand All @@ -134,21 +135,21 @@ Our samples uses 🌶️ to show how easy or complicated those samples are. The
### Networking including HTTP, SSL

* [🌶️ - UdpClient sample pack](samples/UdpClient)
* [🌶️ - WebSocket Client Sample](samples/WebSockets/WebSockets.Client.Sample)
* [🌶️ - WiFI samples](samples/Wifi)
* [🌶️ to 🌶️🌶️ - .NET **nanoFramework** Webserver sample pack](samples/Webserver)
* [🌶️ to 🌶️🌶️ - WebSocket sample pack](samples/WebSockets)
* [🌶️🌶️ - HTTP Listener sample](samples/HTTP/HttpListener)
* [🌶️🌶️ - HTTP sample pack](samples/HTTP)
* [🌶️🌶️ - HTTP WebRequest sample](samples/HTTP/HttpWebRequest)
* [🌶️🌶️ - Networking sample pack](samples/Networking)
* [🌶️🌶️ - WebSocket Server Sample with RGB Led](samples/WebSockets/WebSockets.Server.RgbSample)
* [🌶️🌶️ - WebSocket ServerClient Sample](samples/WebSockets/Websockets.ServerClient.Sample)
* [🌶️🌶️ - Wifi Soft AP sample](samples/WiFiAP)
* [🌶️🌶️ to 🌶️🌶️🌶️ - MQTT sample pack](samples/MQTT)
* [🌶️🌶️ to 🌶️🌶️🌶️ - TLS sample pack](samples/SSL)
* [🌶️🌶️🌶️ - HTTP.HttpAzureGET Sample](samples/HTTP/HttpAzureGET)
* [🌶️🌶️🌶️ - HTTP.HttpAzurePOST Sample](samples/HTTP/HttpAzurePOST)
* [Error](samples/Wifi)
* [Error](samples/WebSockets)
* [Error](samples/WebSockets/WebSockets.Client.Sample)
* [Error](samples/WebSockets/WebSockets.Server.RgbSample)
* [Error](samples/WebSockets/Websockets.ServerClient.Sample)

### Real Time Clock

Expand Down Expand Up @@ -198,12 +199,12 @@ Our samples uses 🌶️ to show how easy or complicated those samples are. The

### USB Client related

* [System.Device.UsbClient sample pack](samples/UsbClient)
* [🌶️🌶️ - System.Device.UsbClient sample pack](samples/UsbClient)

### Wifi

* [🌶️ - WiFI samples](samples/Wifi)
* [🌶️🌶️ - Wifi Soft AP sample](samples/WiFiAP)
* [Error](samples/Wifi)

</devices>

Expand Down
25 changes: 13 additions & 12 deletions README.zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
-----
文档语言: [English](README.md) | [简体中文](README.zh-cn.md)

## 欢迎使用 **nanoFramework** 例程库!
# 欢迎使用 **nanoFramework** 例程库!

本库包括了团队在测试时使用的例程代码,用于验证新增功能以及其它实验室探索。
随意浏览,随心所欲,尽享回报。
Expand Down Expand Up @@ -37,11 +37,12 @@
* [🌶️ - System.Device.PWM sample](samples/PWM)
* [🌶️ - System.Device.Spi sample](samples/SPI)
* [🌶️ to 🌶️🌶️ - System.IO.Ports serial Communication sample](samples/SerialCommunication)
* [🌶️🌶️ - I2C GPS sample](samples/I2C/System.Device.I2c/GPS)
* [🌶️🌶️ - I2C sample sample pack](samples/I2C)
* [🌶️🌶️ - I2C Scanner sample](samples/I2C/NanoI2cScanner)
* [🌶️🌶️ - I2S Microphone sample](samples/I2S/Input)
* [🌶️🌶️ - I2S sample pack](samples/I2S)
* [🌶️🌶️🌶️ - Using Azure SDK with BMP280 on M5Stack with .NET nanoFramework](samples/AzureSDK/AzureSDKSensorCertificate)
* [🌶️🌶️ - I2S Speaker sample](samples/I2S/Output)
* [🌶️🌶️🌶️ - Using Azure SDK with BMP280 on M5Stack with .NET nanoFramework](samples/AzureSDK/AzureSDKSensorCertificate/Readme.md)

### AMQP

Expand All @@ -63,7 +64,7 @@
* [🌶️🌶️🌶️ - Complete Azure MQTT sample using BMP280 sensor **without Azure lib** and with deep sleep](samples/AzureMQTTTwinsBMP280Sleep)
* [🌶️🌶️🌶️ - HTTP.HttpAzureGET Sample](samples/HTTP/HttpAzureGET)
* [🌶️🌶️🌶️ - HTTP.HttpAzurePOST Sample](samples/HTTP/HttpAzurePOST)
* [🌶️🌶️🌶️ - Using Azure SDK with BMP280 on M5Stack with .NET nanoFramework](samples/AzureSDK/AzureSDKSensorCertificate)
* [🌶️🌶️🌶️ - Using Azure SDK with BMP280 on M5Stack with .NET nanoFramework](samples/AzureSDK/AzureSDKSensorCertificate/Readme.md)
* [Azure IoT Device Provisioning Service (DPS) example](samples/AzureSDK/DpsSampleApp)

### Bluetooth
Expand Down Expand Up @@ -113,7 +114,7 @@

* [🌶️🌶️🌶️ - Complete Azure MQTT sample using BMP280 sensor **with** Azure lib and deep sleep](samples/AzureSDK/AzureSDKSleepBMP280)
* [🌶️🌶️🌶️ - Complete Azure MQTT sample using BMP280 sensor **without Azure lib** and with deep sleep](samples/AzureMQTTTwinsBMP280Sleep)
* [🌶️🌶️🌶️ - Using Azure SDK with BMP280 on M5Stack with .NET nanoFramework](samples/AzureSDK/AzureSDKSensorCertificate)
* [🌶️🌶️🌶️ - Using Azure SDK with BMP280 on M5Stack with .NET nanoFramework](samples/AzureSDK/AzureSDKSensorCertificate/Readme.md)

### Interop

Expand All @@ -132,21 +133,21 @@
### Networking including HTTP, SSL

* [🌶️ - UdpClient sample pack](samples/UdpClient)
* [🌶️ - WebSocket 客户端示例](samples/WebSockets/WebSockets.Client.Sample/README.zh-cn.md)
* [🌶️ - WiFI 示例](samples/Wifi/README.zh-cn.md)
* [🌶️ to 🌶️🌶️ - .NET **nanoFramework** Webserver sample pack](samples/Webserver)
* [🌶️ to 🌶️🌶️ - WebSocket示例包](samples/WebSockets/README.zh-cn.md)
* [🌶️🌶️ - HTTP Listener sample](samples/HTTP/HttpListener)
* [🌶️🌶️ - HTTP sample pack](samples/HTTP)
* [🌶️🌶️ - HTTP WebRequest sample](samples/HTTP/HttpWebRequest)
* [🌶️🌶️ - Networking sample pack](samples/Networking)
* [🌶️🌶️ - WebSocket ServerClient Sample](samples/WebSockets/Websockets.ServerClient.Sample/README.zh-cn.md)
* [🌶️🌶️ - WebSocket Server示例与RGB Led](samples/WebSockets/WebSockets.Server.RgbSample/README.zh-cn.md)
* [🌶️🌶️ - Wifi Soft AP sample](samples/WiFiAP)
* [🌶️🌶️ to 🌶️🌶️🌶️ - MQTT sample pack](samples/MQTT)
* [🌶️🌶️ to 🌶️🌶️🌶️ - TLS sample pack](samples/SSL)
* [🌶️🌶️🌶️ - HTTP.HttpAzureGET Sample](samples/HTTP/HttpAzureGET)
* [🌶️🌶️🌶️ - HTTP.HttpAzurePOST Sample](samples/HTTP/HttpAzurePOST)
* [Error](samples/Wifi)
* [Error](samples/WebSockets)
* [Error](samples/WebSockets/WebSockets.Client.Sample)
* [Error](samples/WebSockets/WebSockets.Server.RgbSample)
* [Error](samples/WebSockets/Websockets.ServerClient.Sample)

### Real Time Clock

Expand Down Expand Up @@ -196,12 +197,12 @@

### USB Client related

* [System.Device.UsbClient sample pack](samples/UsbClient)
* [🌶️🌶️ - System.Device.UsbClient sample pack](samples/UsbClient)

### Wifi

* [🌶️ - WiFI 示例](samples/Wifi/README.zh-cn.md)
* [🌶️🌶️ - Wifi Soft AP sample](samples/WiFiAP)
* [Error](samples/Wifi)

</devices>

Expand Down
5 changes: 5 additions & 0 deletions device-listing/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,10 @@ internal class Configuration
/// Gets or sets the list of ignored folders.
/// </summary>
public string[] Ignored { get; set; }

/// <summary>
/// Gets or sets the list of languages to generate.
/// </summary>
public string[] Languages {get; set;}
}
}
4 changes: 4 additions & 0 deletions device-listing/Configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,9 @@
"packages",
"bin",
"obj"
],
"Languages": [
"",
"zh-cn"
]
}
85 changes: 44 additions & 41 deletions device-listing/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,48 +26,50 @@
}

string samplesPath = Path.Combine(repoRoot, "samples");
List<SampleInfo> samples;

List<SampleInfo> samples = new();
// We will iterate one per language
foreach (var language in configuration.Languages)
{
samples = new();

GetAllDirectoriesAndPopulate(Directory.EnumerateDirectories(samplesPath));
GetAllDirectoriesAndPopulate(Directory.EnumerateDirectories(samplesPath), language);

samples.Sort();
samples.Sort();

var allCategories = new HashSet<string>();
var allCategories = new HashSet<string>();

foreach (SampleInfo sample in samples)
{
bool beingDisplayed = false;
foreach (string category in sample.Categories)
foreach (SampleInfo sample in samples)
{
if (allCategories.Add(category))
bool beingDisplayed = false;
foreach (string category in sample.Categories)
{
if (!configuration.Categories.Where(m => m.Name == category).Any())
if (allCategories.Add(category))
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"Warning: Category `{category}` is missing description (`{sample.Title}`). [{sample.ReadmePath}]");
Console.ForegroundColor = ConsoleColor.White;
if (!configuration.Categories.Where(m => m.Name == category).Any())
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"Warning: Category `{category}` is missing description (`{sample.Title}`). [{sample.ReadmePath}]");
Console.ForegroundColor = ConsoleColor.White;
}
}
}

beingDisplayed |= !beingDisplayed && configuration.Categories.Where(m => m.Name == category).Any();
}
beingDisplayed |= !beingDisplayed && configuration.Categories.Where(m => m.Name == category).Any();
}

if (!beingDisplayed && sample.CategoriesFileExists)
{
// We do not want to show the warning when file doesn't exist as you will get separate warning that category.txt is missing in that case.
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"Warning: Sample `{sample.Title}` is not being displayed under any category. [{sample.CategoriesFilePath}]");
Console.ForegroundColor = ConsoleColor.White;
if (!beingDisplayed && sample.CategoriesFileExists)
{
// We do not want to show the warning when file doesn't exist as you will get separate warning that category.txt is missing in that case.
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"Warning: Sample `{sample.Title}` is not being displayed under any category. [{sample.CategoriesFilePath}]");
Console.ForegroundColor = ConsoleColor.White;
}
}
string alphabeticalDevicesIndex = Path.Combine(repoRoot, $"README{(string.IsNullOrEmpty(language) ? string.Empty : $".{language}")}.md");
string categorizedDeviceListing = GetCategorizedDeviceListing(samplesPath, samples);
ReplacePlaceholder(alphabeticalDevicesIndex, "devices", categorizedDeviceListing);
}

string alphabeticalDevicesIndex = Path.Combine(repoRoot, "README.md");
string categorizedDeviceListing = GetCategorizedDeviceListing(samplesPath, samples);
ReplacePlaceholder(alphabeticalDevicesIndex, "devices", categorizedDeviceListing);
alphabeticalDevicesIndex = Path.Combine(repoRoot, "README.zh-cn.md");
ReplacePlaceholder(alphabeticalDevicesIndex, "devices", categorizedDeviceListing);

string GetDeviceListing(string devicesPath, IEnumerable<SampleInfo> samples)
{
var deviceListing = new StringBuilder();
Expand All @@ -87,7 +89,7 @@ string GetCategorizedDeviceListing(string devicesPath, IEnumerable<SampleInfo> d
var categoryDescription = configuration.Categories.Where(m => m.Name == categoryToDisplay).FirstOrDefault()?.Description;
if (!string.IsNullOrEmpty(categoryDescription))
{
string listingInCurrentCategory = GetDeviceListing(devicesPath, devices.Where((d) => d.Categories.Contains(categoryToDisplay)));
string listingInCurrentCategory = GetDeviceListing(devicesPath, devices.Where(d => d.Categories.Contains(categoryToDisplay)));
if (!string.IsNullOrEmpty(listingInCurrentCategory))
{
sampleListing.AppendLine($"### {categoryDescription}");
Expand Down Expand Up @@ -173,7 +175,7 @@ void ReplacePlaceholder(string filePath, string placeholderName, string newConte
fileContent.Substring(endIdx));
}

void GetAllDirectoriesAndPopulate(IEnumerable<string> path)
void GetAllDirectoriesAndPopulate(IEnumerable<string> path, string language)
{
foreach (string directory in path)
{
Expand All @@ -182,11 +184,19 @@ void GetAllDirectoriesAndPopulate(IEnumerable<string> path)
continue;
}

string readme = Path.Combine(directory, "README.md");
string categories = Path.Combine(directory, "category.txt");

if (File.Exists(readme))
// Find the README.xx.md files
var files = Directory.EnumerateFiles(directory, $"README{(string.IsNullOrEmpty(language) ? string.Empty : $".{language}")}.md");
// If we don't have any, then fall back to the neutral langauge
if (!files.Any())
{
files = Directory.EnumerateFiles(directory, "README.md");
}

foreach (var readme in files)
{
// string readme = Path.Combine(directory, "README.md");
var device = new SampleInfo(readme, categories);

if (device.Title == null)
Expand All @@ -196,15 +206,8 @@ void GetAllDirectoriesAndPopulate(IEnumerable<string> path)
}

samples.Add(device);
}
else
{
if (File.Exists(categories))
{
Console.WriteLine($"Warning: Device directory does not have a README.md file. [{directory}]");
}
}

GetAllDirectoriesAndPopulate(Directory.EnumerateDirectories(directory));
GetAllDirectoriesAndPopulate(Directory.EnumerateDirectories(directory), language);
}
}
}
31 changes: 28 additions & 3 deletions device-listing/SampleInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class SampleInfo : IComparable<SampleInfo>
public HashSet<string> Categories { get; private set; } = new HashSet<string>();
public string CategoriesFilePath { get; private set; }
public bool CategoriesFileExists { get; private set; }
public string Language { get; private set; }

public SampleInfo(string readmePath, string categoriesFilePath)
{
Expand All @@ -25,6 +26,7 @@ public SampleInfo(string readmePath, string categoriesFilePath)
Title = GetTitle(readmePath) ?? "Error";
CategoriesFilePath = categoriesFilePath;
CategoriesFileExists = File.Exists(categoriesFilePath);
Language = FindLanguage(readmePath);

ImportCategories();
}
Expand All @@ -34,6 +36,23 @@ public int CompareTo(SampleInfo? other)
return Title.CompareTo(other?.Title);
}

public string FindLanguage(string filepath)
{
// Pattern is like path\name.zn-cn.ext or path\name.ext
var separator = Path.DirectorySeparatorChar;
var file = filepath.Substring(filepath.LastIndexOf(separator) + 1);
var filewithoutext = file.Substring(0, file.LastIndexOf('.'));
var posdot = filewithoutext.LastIndexOf('.');
// We do have another dot, so by convention, it does contain our langage
if (posdot > 0)
{
return filewithoutext.Substring(posdot + 1);
}

// Neutral language by convention
return string.Empty;
}

private void ImportCategories()
{
if (!CategoriesFileExists)
Expand All @@ -59,10 +78,16 @@ private void ImportCategories()
private static string? GetTitle(string readmePath)
{
string[] lines = File.ReadAllLines(readmePath);
if (lines[0].StartsWith("# "))
int inc = 0;
do
{
return lines[0].Substring(2);
}
if (lines[inc].StartsWith("# "))
{
return lines[inc].Substring(2);
}

inc++;
} while (inc < lines.Length);

return null;
}
Expand Down
1 change: 1 addition & 0 deletions samples/I2S/Input/category.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
device
1 change: 1 addition & 0 deletions samples/I2S/Output/category.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
device
2 changes: 1 addition & 1 deletion samples/UsbClient/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# System.Device.UsbClient sample pack
# 🌶️🌶️ - System.Device.UsbClient sample pack

Shows how to use the [System.Device.UsbClient](http://docs.nanoframework.net/api/System.Device.UsbClient.html) API to use the various USB client classes.

Expand Down

0 comments on commit 875dba8

Please sign in to comment.