Skip to main content

2024-09-17

One-liner

有些梦想虽然遥不可及,但不是不可能实现。只要我足够的强。 --- 《秦时明月》 · 小学生


English

once again : 再次

It's again possible : 再次可行

PowerShell: Export Directory Permission List

To export the user permission list for the first-level subdirectories in D:\Sharing_Data, you can use PowerShell or the Command Prompt with the icacls tool. Below are the detailed steps for both methods:


Method 1: Using PowerShell

  1. Open PowerShell

    • Press Win + X, and select Windows PowerShell (Admin) or Windows Terminal (Admin).
  2. Run the following script

    # Set the shared directory path
    $sharedPath = "D:\Sharing_Data"

    # Get first-level subdirectories
    $subDirectories = Get-ChildItem -Path $sharedPath -Directory

    # Create an empty array to store permission info
    $permissionsList = @()

    foreach ($dir in $subDirectories) {
    # Get the current subdirectory's ACL (Access Control List)
    $acl = Get-Acl -Path $dir.FullName

    foreach ($access in $acl.Access) {
    # Create a custom object to store info
    $permission = [PSCustomObject]@{
    Directory = $dir.Name
    Identity = $access.IdentityReference
    FileSystemRights = $access.FileSystemRights
    AccessControlType = $access.AccessControlType
    }
    # Add to the array
    $permissionsList += $permission
    }
    }

    # Export to CSV file
    $permissionsList | Export-Csv -Path "D:\Sharing_Data_Permissions.csv" -NoTypeInformation -Encoding UTF8

    Write-Output "Permission list has been successfully exported to D:\Sharing_Data_Permissions.csv"
  3. Script Explanation

    • Retrieve Subdirectories: Get-ChildItem -Path $sharedPath -Directory retrieves all first-level subdirectories under D:\Sharing_Data.
    • Retrieve Permissions: Get-Acl retrieves the permission info for each subdirectory.
    • Organize Data: Directory names, users, and permission types are organized into a table format.
    • Export to CSV: The organized permission information is exported to D:\Sharing_Data_Permissions.csv.
  4. View the Exported Permission File

    You can open the D:\Sharing_Data_Permissions.csv file using Excel or any CSV-compatible application for easy viewing and analysis.


Method 2: Using icacls in Command Prompt

  1. Open Command Prompt

    • Press Win + R, type cmd, and press Enter.
  2. Run the following command

    cd /d D:\Sharing_Data
    for /D %G in (*) do icacls "%G" >> D:\Sharing_Data_Permissions.txt

    Note:

    • If you are writing this command in a batch file (.bat), replace %G with %%G:
      for /D %%G in (*) do icacls "%%G" >> D:\Sharing_Data_Permissions.txt
  3. Command Explanation

    • for /D %G in (*): Loops through all first-level subdirectories under D:\Sharing_Data.
    • icacls "%G": Retrieves the permission information for each subdirectory.
    • >> D:\Sharing_Data_Permissions.txt: Appends the permission info to D:\Sharing_Data_Permissions.txt.
  4. View the Exported Permission File

    Open the D:\Sharing_Data_Permissions.txt file to view the permission list for each subdirectory.


Which Method to Choose?

  • The PowerShell method is more flexible and powerful, suitable for scenarios where further processing or analysis of permission data is required.
  • The icacls method is quick and simple, ideal for rapidly exporting permission information to a text file.

Choose the method that best fits your needs. If you need detailed or formatted permission data, the PowerShell method is recommended.


Additional Tips

  • Administrator Privileges: Ensure you run PowerShell or Command Prompt as an administrator to avoid permission issues when reading certain directories.
  • Encoding Issues: Use UTF-8 encoding when exporting to a CSV file to prevent Chinese characters from displaying as garbled text.
  • Permission Description:
    • IdentityReference: Represents the user or user group.
    • FileSystemRights: Specifies the type of permission, such as read, write, modify, etc.
    • AccessControlType: Specifies whether the permission is allowed (Allow) or denied (Deny).

Developing a Gradle Plugin

To create a custom Gradle plugin called codegen-jooq-gradle-plugin with plugin ID org.moonlit.jooq, which adds default configurations to the gradle-jooq-plugin, you can follow the steps below. The process includes setting up the plugin project, defining the plugin logic, adding default configurations, and packaging and publishing the plugin.

Below are the detailed steps with code examples:


1. Create the Plugin Project

Start by creating a new Gradle project to develop your plugin.

mkdir codegen-jooq-gradle-plugin
cd codegen-jooq-gradle-plugin
gradle init --type java-gradle-plugin

This will generate a basic structure for your Gradle plugin project.


2. Configure build.gradle

Next, edit the build.gradle file to add the necessary dependencies and plugin information.

plugins {
id 'java-gradle-plugin'
id 'maven-publish'
id 'java'
}

group = 'org.moonlit'
version = '1.0.0'

repositories {
mavenCentral()
}

dependencies {
implementation 'org.jooq:jooq:3.18.4' // Adjust version as needed
implementation 'nu.studer:gradle-jooq-plugin:5.2.1' // Use the appropriate version of gradle-jooq-plugin
}

gradlePlugin {
plugins {
codegenJooq {
id = 'org.moonlit.jooq'
implementationClass = 'org.moonlit.jooq.CodegenJooqPlugin'
displayName = 'Codegen JOOQ Gradle Plugin'
description = 'A custom Gradle plugin that extends gradle-jooq-plugin with default configurations.'
}
}
}

publishing {
publications {
pluginMaven(MavenPublication) {
from components.java
groupId = 'org.moonlit'
artifactId = 'codegen-jooq-gradle-plugin'
version = '1.0.0'
}
}
repositories {
mavenLocal()
// Add remote repository configuration if needed
// maven {
// url = uri("https://your.repository.url")
// credentials {
// username = project.findProperty("repoUser") ?: ""
// password = project.findProperty("repoPassword") ?: ""
// }
// }
}
}

Explanation:

  • The gradlePlugin block defines the plugin ID and implementation class.
  • The publishing block configures Maven publishing to allow distribution of the plugin locally or to a remote repository.

3. Implement the Plugin Logic

Now, create the plugin implementation file. In the directory src/main/java/org/moonlit/jooq/, create CodegenJooqPlugin.java.

package org.moonlit.jooq;

import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.jooq.gradle.JooqGenerate;
import nu.studer.gradle.jooq.JooqPluginExtension;

public class CodegenJooqPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
// Apply the original gradle-jooq-plugin
project.getPluginManager().apply("nu.studer.jooq");

// Get the Jooq plugin extension
JooqPluginExtension jooqExtension = project.getExtensions().getByType(JooqPluginExtension.class);

// Set default configurations
jooqExtension.getVersion().convention("3.18.4"); // Default JOOQ version

jooqExtension.generateAll(generate -> {
generate.getInputSchema().convention("public");
generate.getOutputDirectory().convention(new File(project.getBuildDir(), "generated-jooq"));
generate.getGenerator().getName().convention("org.jooq.codegen.DefaultGenerator");
generate.getGenerator().getStrategy().getName().convention("org.jooq.codegen.DefaultGeneratorStrategy");
});

// More default configurations can be added, such as database connection settings
}
}

Explanation:

  • This code applies the gradle-jooq-plugin and adds default configurations for schema, output directory, and generator strategy.

4. Configure Plugin Metadata

Ensure that the plugin metadata file exists at resources/META-INF/gradle-plugins/org.moonlit.jooq.properties with the following content:

implementation-class=org.moonlit.jooq.CodegenJooqPlugin

This informs Gradle about the plugin’s implementation class.


5. Package and Publish the Plugin

Local Publishing

To publish the plugin to your local Maven repository for testing:

./gradlew publishToMavenLocal

Remote Publishing

If you want to publish the plugin to Maven Central or another remote repository, ensure that the publishing block in build.gradle is correctly configured with credentials and repository URLs.


6. Use the Plugin

To use the plugin in another project, follow these steps:

1. Add Plugin Repository to settings.gradle

If the plugin has been published to Maven Central or another repository, add the repository in settings.gradle:

pluginManagement {
repositories {
gradlePluginPortal()
mavenLocal()
mavenCentral()
}
}

2. Apply the Plugin in build.gradle

plugins {
id 'org.moonlit.jooq' version '1.0.0'
}

// Minimal configuration needed as default values are pre-configured
jooq {
version = '3.18.4' // Optional, only if you want to override the default version
configurations {
main {
jdbc {
driver = 'org.postgresql.Driver'
url = 'jdbc:postgresql://localhost:5432/mydb'
user = 'username'
password = 'password'
}
generator {
database {
inputSchema = 'public'
}
target {
packageName = 'com.example.jooq'
directory = "${project.buildDir}/generated-jooq"
}
}
}
}
}

3. Generate JOOQ Classes

Run the following command to generate the JOOQ classes:

./gradlew generateJooq

7. Increase Flexibility with Custom Extension

If you want the plugin to be more flexible and allow users to override default configurations, you can modify the plugin as follows:

package org.moonlit.jooq;

import org.gradle.api.Plugin;
import org.gradle.api.Project;
import nu.studer.gradle.jooq.JooqPluginExtension;

public class CodegenJooqPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getPluginManager().apply("nu.studer.jooq");

JooqPluginExtension jooqExtension = project.getExtensions().getByType(JooqPluginExtension.class);

jooqExtension.getVersion().convention("3.18.4");

jooqExtension.configurations().all(configuration -> {
configuration.generate(generate -> {
generate.getInputSchema().convention("public");
generate.getOutputDirectory().convention(new File(project.getBuildDir(), "generated-jooq"));
generate.getGenerator().getName().convention("org.jooq.codegen.DefaultGenerator");
});
});
}
}

Explanation:

  • Users can override the default configurations as needed in their build.gradle file.

8. Version Control and Continuous Integration

To ensure plugin versioning and CI/CD processes:

  • Use Git for version control.
  • Set up a CI/CD pipeline (e.g., GitHub Actions, GitLab CI) to automate testing and publishing.
  • Follow Semantic Versioning (SemVer) to manage plugin versions.

9. Example Project

To help users understand how to use the plugin, create an example project with instructions in the README.md.

Example Project Structure

example-project/
├── build.gradle
├── settings.gradle
└── src/
└── main/
└── java/

Example build.gradle

plugins {
id 'org.moonlit.jooq' version '1.0.0'
}

repositories {
mavenLocal()
mavenCentral()
}

jooq {
configurations {
main {
jdbc {
driver = 'org.postgresql.Driver'
url = 'jdbc:postgresql://localhost:5432/mydb'
user = 'username'
password = 'password'
}
generator {
database {
inputSchema = 'public'
}
target {
packageName = 'com.example.jooq'
}
}
}
}
}

Summary

By following these steps, you can develop a custom Gradle plugin codegen-jooq-gradle-plugin that extends gradle-jooq-plugin with default configurations. Make sure to thoroughly test the plugin during development and provide clear documentation for users to enhance the usability of your plugin.

For more information, you can refer to:

Testing a Gradle Plugin Project

When developing the codegen-jooq-gradle-plugin, it's important to test the plugin to ensure it works as expected in different configurations. This guide covers how to configure a testing environment, create test classes, and execute them using Gradle TestKit.

1. Configure the Testing Environment

Start by ensuring that your build.gradle file contains the necessary dependencies and configuration for testing.

Modify build.gradle

plugins {
id 'java-gradle-plugin'
id 'maven-publish'
id 'java'
}

group = 'org.moonlit'
version = '1.0.0'

repositories {
mavenCentral()
}

dependencies {
implementation 'org.jooq:jooq:3.18.4'
implementation 'nu.studer:gradle-jooq-plugin:5.2.1'

// Testing dependencies
testImplementation gradleTestKit() // For testing the Gradle plugin
testImplementation 'junit:junit:4.13.2' // Using JUnit 4 for testing
// If you want to use JUnit 5:
// testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'
}

gradlePlugin {
plugins {
codegenJooq {
id = 'org.moonlit.jooq'
implementationClass = 'org.moonlit.jooq.CodegenJooqPlugin'
displayName = 'Codegen JOOQ Gradle Plugin'
description = 'A custom Gradle plugin that extends gradle-jooq-plugin with default configurations.'
}
}
}

publishing {
publications {
pluginMaven(MavenPublication) {
from components.java
groupId = 'org.moonlit'
artifactId = 'codegen-jooq-gradle-plugin'
version = '1.0.0'
}
}
repositories {
mavenLocal()
}
}

// Use JUnit 4 for testing
test {
useJUnit()
// If using JUnit 5:
// useJUnitPlatform()
}

Explanation:

  • The testImplementation gradleTestKit() dependency enables you to use Gradle TestKit for plugin testing.
  • You can choose between JUnit 4 or JUnit 5 for writing your tests by configuring the corresponding dependencies and test {} block.

2. Create a Test Class

Next, you will create a test class that uses Gradle TestKit to validate your plugin's behavior.

Directory Structure

Ensure your project structure looks like this:

codegen-jooq-gradle-plugin/
├── build.gradle
├── settings.gradle
├── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── moonlit/
│ │ └── jooq/
│ │ └── CodegenJooqPlugin.java
│ └── test/
│ └── java/
│ └── org/
│ └── moonlit/
│ └── jooq/
│ └── CodegenJooqPluginTest.java

Writing the Test Class

Create CodegenJooqPluginTest.java under src/test/java/org/moonlit/jooq/.

package org.moonlit.jooq;

import org.gradle.testkit.runner.GradleRunner;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.TaskOutcome;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

import static org.junit.Assert.*;

public class CodegenJooqPluginTest {

@Rule
public final TemporaryFolder testProjectDir = new TemporaryFolder(); // To isolate test environments

private File buildFile;

@Test
public void testPluginAppliesSuccessfully() throws IOException {
// Create a temporary project directory
File projectDir = testProjectDir.getRoot();

// Create a build.gradle file
buildFile = testProjectDir.newFile("build.gradle");
String buildFileContent = "plugins {\n" +
" id 'org.moonlit.jooq'\n" +
"}\n" +
"\n" +
"repositories {\n" +
" mavenCentral()\n" +
"}\n" +
"\n" +
"jooq {\n" +
" configurations {\n" +
" main {\n" +
" jdbc {\n" +
" driver = 'org.h2.Driver'\n" +
" url = 'jdbc:h2:mem:testdb'\n" +
" user = 'sa'\n" +
" password = ''\n" +
" }\n" +
" generator {\n" +
" name = 'org.jooq.codegen.DefaultGenerator'\n" +
" strategy {\n" +
" name = 'org.jooq.codegen.DefaultGeneratorStrategy'\n" +
" }\n" +
" database {\n" +
" name = 'org.jooq.meta.h2.H2Database'\n" +
" inputSchema = 'PUBLIC'\n" +
" }\n" +
" generate {\n" +
" daos = true\n" +
" records = true\n" +
" immutablePojos = true\n" +
" }\n" +
" target {\n" +
" packageName = 'com.example.jooq'\n" +
" directory = '${project.buildDir}/generated-jooq'\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
"}\n";

Files.write(buildFile.toPath(), buildFileContent.getBytes());

// Run the Gradle task
BuildResult result = GradleRunner.create()
.withProjectDir(projectDir)
.withPluginClasspath()
.withArguments("generateJooq")
.build();

// Assert the task succeeded
assertEquals(TaskOutcome.SUCCESS, result.task(":generateJooq").getOutcome());
}

@Test
public void testPluginConfiguration() throws IOException {
// Create another temporary project directory
File projectDir = testProjectDir.getRoot();

// Create a build.gradle file with custom configurations
buildFile = testProjectDir.newFile("build.gradle");
String buildFileContent = "plugins {\n" +
" id 'org.moonlit.jooq'\n" +
"}\n" +
"\n" +
"repositories {\n" +
" mavenCentral()\n" +
"}\n" +
"\n" +
"jooq {\n" +
" configurations {\n" +
" main {\n" +
" jdbc {\n" +
" driver = 'org.h2.Driver'\n" +
" url = 'jdbc:h2:mem:testdb'\n" +
" user = 'sa'\n" +
" password = ''\n" +
" }\n" +
" generator {\n" +
" target {\n" +
" packageName = 'com.custom.jooq'\n" +
" directory = '${project.buildDir}/custom-generated-jooq'\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
"}\n";

Files.write(buildFile.toPath(), buildFileContent.getBytes());

// Run the Gradle task
BuildResult result = GradleRunner.create()
.withProjectDir(projectDir)
.withPluginClasspath()
.withArguments("generateJooq")
.build();

// Assert the task succeeded
assertEquals(TaskOutcome.SUCCESS, result.task(":generateJooq").getOutcome());

// Verify the output directory exists
File generatedDir = new File(projectDir, "build/custom-generated-jooq");
assertTrue(generatedDir.exists());
}
}

Explanation:

  • TemporaryFolder ensures that each test has its own isolated directory for creating temporary projects.
  • testPluginAppliesSuccessfully(): This test verifies that the plugin can be applied successfully and runs the generateJooq task.
  • testPluginConfiguration(): This test checks if the plugin works with custom configurations and verifies the output.

3. Run the Tests

To execute the tests, run the following command from your project root:

./gradlew test

Gradle will run the tests and generate a report in build/reports/tests/test/index.html.


4. Use JUnit 5 (Optional)

If you prefer JUnit 5 over JUnit 4, you can update your configuration as follows:

Modify build.gradle

dependencies {
implementation 'org.jooq:jooq:3.18.4'
implementation 'nu.studer:gradle-jooq-plugin:5.2.1'

// JUnit 5 dependency
testImplementation gradleTestKit()
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'
}

test {
useJUnitPlatform() // Enable JUnit 5 platform
}

Example JUnit 5 Test Class

package org.moonlit.jooq;

import org.gradle

.testkit.runner.GradleRunner;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.TaskOutcome;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

import static org.junit.jupiter.api.Assertions.*;

public class CodegenJooqPluginJUnit5Test {

@TempDir
File testProjectDir;

private File buildFile;

@Test
public void testPluginAppliesSuccessfully() throws IOException {
buildFile = new File(testProjectDir, "build.gradle");
String buildFileContent = "plugins {\n" +
" id 'org.moonlit.jooq'\n" +
"}\n" +
"\n" +
"repositories {\n" +
" mavenCentral()\n" +
"}\n" +
"\n" +
"jooq {\n" +
" configurations {\n" +
" main {\n" +
" jdbc {\n" +
" driver = 'org.h2.Driver'\n" +
" url = 'jdbc:h2:mem:testdb'\n" +
" user = 'sa'\n" +
" password = ''\n" +
" }\n" +
" generator {\n" +
" name = 'org.jooq.codegen.DefaultGenerator'\n" +
" strategy {\n" +
" name = 'org.jooq.codegen.DefaultGeneratorStrategy'\n" +
" }\n" +
" database {\n" +
" name = 'org.jooq.meta.h2.H2Database'\n" +
" inputSchema = 'PUBLIC'\n" +
" }\n" +
" generate {\n" +
" daos = true\n" +
" records = true\n" +
" immutablePojos = true\n" +
" }\n" +
" target {\n" +
" packageName = 'com.example.jooq'\n" +
" directory = '${project.buildDir}/generated-jooq'\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
"}\n";

Files.write(buildFile.toPath(), buildFileContent.getBytes());

// Run the Gradle task
BuildResult result = GradleRunner.create()
.withProjectDir(testProjectDir)
.withPluginClasspath()
.withArguments("generateJooq")
.build();

assertEquals(TaskOutcome.SUCCESS, result.task(":generateJooq").getOutcome());
}
}

5. Expand Tests

You can add additional tests to cover more scenarios, such as:

  • Default Configuration Tests: Verify that default values are applied correctly when no custom configurations are provided.
  • Custom Configuration Tests: Validate that the plugin correctly applies user-provided configurations.
  • Error Handling Tests: Ensure the plugin provides helpful error messages when misconfigured.

Example Test for Default Configuration

@Test
public void testDefaultConfiguration() throws IOException {
buildFile = testProjectDir.newFile("build.gradle");
String buildFileContent = "plugins {\n" +
" id 'org.moonlit.jooq'\n" +
"}\n" +
"\n" +
"repositories {\n" +
" mavenCentral()\n" +
"}\n";

Files.write(buildFile.toPath(), buildFileContent.getBytes());

BuildResult result = GradleRunner.create()
.withProjectDir(testProjectDir.getRoot())
.withPluginClasspath()
.withArguments("generateJooq")
.build();

assertEquals(TaskOutcome.SUCCESS, result.task(":generateJooq").getOutcome());

File generatedDir = new File(testProjectDir.getRoot(), "build/generated-jooq");
assertTrue(generatedDir.exists());
}

6. Continuous Integration (CI)

To ensure your plugin works across different environments and code changes, set up a CI pipeline using tools like GitHub Actions. Here's an example GitHub Actions configuration:

GitHub Actions Workflow

Create a .github/workflows/gradle.yml file:

name: Gradle CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Build with Gradle
run: ./gradlew build

Summary

By following these steps, you can effectively test your Gradle plugin and ensure it works correctly in various scenarios. Key points include:

  1. Testing Environment: Set up dependencies using Gradle TestKit and JUnit.
  2. Test Classes: Create isolated tests for validating plugin behavior.
  3. Test Execution: Use ./gradlew test to run tests and verify results.
  4. CI Integration: Automate testing using GitHub Actions or another CI tool.

This setup will help you maintain a high-quality Gradle plugin.