Skip to content

Instantly share code, notes, and snippets.

@s1037989
Created April 18, 2025 09:44
Show Gist options
  • Save s1037989/762fbab262aa1b95ebf2f5e29a24e71a to your computer and use it in GitHub Desktop.
Save s1037989/762fbab262aa1b95ebf2f5e29a24e71a to your computer and use it in GitHub Desktop.
JFrog Artifactory doesn't have a Perl repository type, which would regenerate a new set of Perl modules index files on every artifact change in the repository. Create a Jfrog Artifactory plugin that will regenerate the Perl index files every type a file is added, removed or modified in order to allow Artifactory to become a "DarkPAN", or offline CPAN.
ChatGPT said:
To enable JFrog Artifactory to act as a DarkPAN (a private/offline CPAN mirror), you can write a user plugin that listens to events like artifact deployment, deletion, or modification, and then regenerates the required Perl index files (such as 02packages.details.txt.gz, etc.).
πŸ›  Plugin Strategy
We'll create a User Plugin in Groovy that:
Hooks into the afterCreate, afterDelete, and afterMove events.
When any of those events occur in a specified repository (e.g., perl-local), the plugin will:
Call a custom script (likely written in Perl or Python) to regenerate the CPAN-style index files.
These index files will be uploaded back to the root of the repository.
πŸ“ Directory Structure
$ARTIFACTORY_HOME/etc/plugins/
└── PerlIndexer.groovy
$ARTIFACTORY_HOME/etc/perl/
└── regenerate_index.pl (or .sh)
🧩 PerlIndexer.groovy Plugin
import org.artifactory.repo.RepoPath
import org.artifactory.fs.FileInfo
import org.artifactory.request.Request
import org.artifactory.request.RequestThreadLocal
import org.artifactory.resource.ResourceStreamHandle
class PerlIndexer {
def perlRepo = "perl-local" // Change this to your repo name
def indexScriptPath = "/opt/artifactory/extra/perl/regenerate_index.pl"
// Trigger after artifact is created
def afterCreate(event) {
if (event.repoPath.repoKey == perlRepo) {
log.info "Artifact created in Perl repo: ${event.repoPath}"
regenerateIndex()
}
}
// Trigger after artifact is deleted
def afterDelete(event) {
if (event.repoPath.repoKey == perlRepo) {
log.info "Artifact deleted in Perl repo: ${event.repoPath}"
regenerateIndex()
}
}
// Optional: after move/rename
def afterMove(event) {
if (event.repoPath.repoKey == perlRepo || event.targetRepoPath.repoKey == perlRepo) {
log.info "Artifact moved in Perl repo: ${event.repoPath} -> ${event.targetRepoPath}"
regenerateIndex()
}
}
private void regenerateIndex() {
try {
def process = ["perl", indexScriptPath, perlRepo].execute()
process.waitFor()
if (process.exitValue() == 0) {
log.info "Perl index regeneration completed successfully."
} else {
log.error "Perl index regeneration failed: ${process.err.text}"
}
} catch (Exception e) {
log.error("Error running index regeneration script", e)
}
}
}
πŸ” Example Perl Script (regenerate_index.pl)
You'll need to:
Walk the directory tree (or use the Artifactory REST API).
Collect package/module info (using Parse::PMFile, CPAN::PackageDetails, etc.).
Write CPAN-style index files.
Example stub (can be expanded):
#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
use CPAN::PackageDetails;
my $repo_path = "/var/opt/jfrog/artifactory/data/repositories/$ARGV[0]";
my @pm_files;
find(
sub {
push @pm_files, $File::Find::name if /\.pm$/;
},
$repo_path
);
my $index_file = "$repo_path/02packages.details.txt";
open my $fh, '>', $index_file or die "Cannot write index file: $!";
print $fh <<'HEADER';
File: 02packages.details.txt
Description: Perl modules index
Columns: package name, version, path
Intended-For: Automated fetch routines, namespace documentation.
Written-By: Artifactory Perl Plugin
Line-Count: TBD
Last-Updated: TBD
HEADER
foreach my $file (@pm_files) {
# Naive example: extract name/version from path
if ($file =~ m{/$ARGV[0]/lib/(.+)\.pm$}) {
my $module = $1;
$module =~ s{/}{::}g;
print $fh "$module 0.01 $file\n";
}
}
close $fh;
# Gzip it
system("gzip -f $index_file");
βœ… Steps to Deploy
Put PerlIndexer.groovy into: $ARTIFACTORY_HOME/etc/plugins/
Place the Perl/Python indexing script where defined in the plugin.
Ensure the script has execution permissions: chmod +x
Reload plugins:
curl -uadmin:password -X POST "http://localhost:8081/artifactory/api/plugins/reload"
πŸ”„ Optional Enhancements
Use Artifactory REST API in the Perl script instead of direct FS access.
Add support for .tar.gz CPAN distributions and extract .pm files from them.
Automate tests to validate index correctness.
Create a REST endpoint in the plugin to manually trigger regeneration.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment