Created
April 18, 2025 09:44
-
-
Save s1037989/762fbab262aa1b95ebf2f5e29a24e71a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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