Horcrux7
Horcrux7

Reputation: 24447

How can I migrate JCenter artifact to the Sonatype Maven repository?

The JCenter Maven repository will be down in some month.

https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter/?utm_source=mkto&utm_medium=email&utm_campaign=bintray-sunset&utm_content=global-02-2021

How can I migrate all artifact to Sonatype before it will be deleted.

Upvotes: 2

Views: 350

Answers (1)

Horcrux7
Horcrux7

Reputation: 24447

I have solve this with multiple steps:

  • First I have written a Java program to download all the artifacts from my JCenter account.
  • Then I have write a Gradle script with the Maven plugin. This script use archiveBaseName, version and the directory of the artifacts as parameters. The script and maven plugin add all the missing things like the PGP signature.
  • Then I write a Java program that iterate over the downloaded artifacts (or a part of it) and call the Gradle script with the parameters archiveBaseName, version and the directory with the artifacts in a loop.
  • On the Sonatype GUI I deploy the uploaded files. Multiple version at once.

The follow code snippet which I have used will not work out of the box because it used internal private API. But it can help as start point. Of course you need an sonatype account and a gpg ring file. The secret properties are saved in the gradle.properties. You need also to customize the group name that the company used in all 3 files.

Downloader

package tool;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Nonnull;

import com.inet.lib.util.IOFunctions;

public class DownloadJCenter {

    // this path will be cut on save
    private static String basePath;

    private static File   root;

    public static void main( String[] args ) throws IOException {
        basePath = "/";
        URL startURL = new URL( "https://jcenter.bintray.com/com/company/" );
        root = new File( "jcenter" );
        load( startURL );
    }

    /**
     * Load the URL iterative
     * 
     * @param parent the URL to load
     * @throws IOException if any error occur
     */
    static void load( @Nonnull URL parent ) throws IOException {
        System.err.println( parent );
        InputStream input = IOFunctions.openStreamSupportingRedirect( parent, 5000 );
        String content = IOFunctions.readString( input, StandardCharsets.UTF_8 );
        List<URL> urls = extractUrls( parent, content );
        for( URL url : urls ) {
            String path = url.getPath();
            if( path.endsWith( "/" ) ) {
                load( url );
            } else {
                input = IOFunctions.openStreamSupportingRedirect( url, 5000 );
                byte[] bytes = IOFunctions.readBytes( input );
                File file = new File( root, path.substring( basePath.length() ) );
                file.getParentFile().mkdirs();
                try (FileOutputStream fos = new FileOutputStream( file )) {
                    fos.write( bytes );
                }
            }
        }
    }

    /**
     * Extract the URLs from the content of page
     * 
     * @param parent the parent URL for relative URLs
     * @param content the page content
     * @return list of found URLs
     * @throws IOException if any error occur
     */
    @Nonnull
    static List<URL> extractUrls( URL parent, @Nonnull String content ) throws IOException {
        ArrayList<URL> result = new ArrayList<>();
        int idx = 0;
        while( true ) {
            int idx1 = content.indexOf( "href=\"", idx );
            if( idx1 < 0 ) {
                break;
            }
            idx1 += 6;
            int idx2 = content.indexOf( "\"", idx1 );
            String urlStr = content.substring( idx1, idx2 );
            if( !urlStr.startsWith( ".." ) ) {
                result.add( new URL( parent, urlStr ) );
            }
            idx = idx2;
        }
        return result;
    }
}

Gradle Launcher

package tool;

import java.io.File;
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import java.util.ArrayList;
import java.util.HashMap;

import com.inet.error.ErrorCode;
import com.inet.lib.util.IOFunctions;
import com.inet.shared.utils.Version;

/**
 * Deploy to the Sonatype server.
 */
public class DeploySonatype {

    private static final String gradle = "C:/Users/...../gradle-6.7.1/bin/gradle.bat";

    public static void main( String[] args ) throws IOException {
        File root = new File( "jcenter/com/company" );
        for( File file : root.listFiles() ) {
            if( file.isDirectory() ) {
                String archivesBaseName = file.getName();
                deployLibrary( archivesBaseName, file );
            }
        }
    }

    static void deployLibrary( String archivesBaseName, File libraryDir ) throws IOException {
        HashMap<Version,File> versionDirs = new HashMap<>();
        for( File file : libraryDir.listFiles() ) {
            if( file.isDirectory() ) {
                versionDirs.put( new Version( file.getName()), file );
            }
        }

        ArrayList<Version> versions = new ArrayList( versionDirs.keySet() );
        versions.sort( null );// old versions first

        for( Version version : versions ) {
            File dir = versionDirs.get( version );
            deployVersion( archivesBaseName, version, dir );
        }
    }

    static void deployVersion( String archivesBaseName, Version version, File dir ) throws IOException {
        System.err.println( archivesBaseName + " " + version + " " + dir );

        File script = IOFunctions.getFile( DeploySonatype.class.getResource( "deploy.gradle" ) );
        IOFunctions.deleteDir( new File( script.getParent(), "build" ) ); // clean from previous run

        ArrayList<String> command = new ArrayList<>();
        command.add( gradle );
        command.add( "-b" );
        command.add( "\"" + script.getPath() + "\"" );
        command.add( "--stacktrace" );
        command.add( "-ParchivesBaseName=" + archivesBaseName );
        command.add( "-Pversion=" + version );
        command.add( "-PartifactDir=" + dir.getAbsolutePath() );

        command.add( "uploadArchives" );

        System.err.println( command );

        ProcessBuilder processBuilder = new ProcessBuilder( command );
        processBuilder.redirectOutput( Redirect.INHERIT );
        processBuilder.redirectError( Redirect.INHERIT );
        processBuilder.environment().put( "JAVA_HOME", System.getProperty( "java.home" ) );
        Process start = processBuilder.start();
        try {
            int exitValue = start.waitFor();
            if( exitValue != 0 ) {
                throw new IOException( "Exit Value: " + exitValue );
            }
        } catch( InterruptedException ex ) {
            ErrorCode.throwAny( ex );
        }
    }
}

deploy.gradle

/****************************************
 * Deploy to Maven
 ****************************************/
apply plugin: 'maven'
apply plugin: 'signing'

group = 'com.company'
println archivesBaseName + "/" + version + "  -> " + artifactDir // come from Java as parameter

task copyArtifact(type: Copy) {
    from file( artifactDir )
    into file("$buildDir/artifacts" )
}

task setupArchives {
    dependsOn copyArtifact
    doLast {
        artifacts {
            fileTree( dir: file( "$buildDir/artifacts" ) ).each {
                archives file: it
                println "\t" + it
            }
        }
        signing {
            if (project.hasProperty("signing.keyId") ){
                sign configurations.archives
            }
        }
    }
}

uploadArchives {
    dependsOn setupArchives

    repositories {
        mavenDeployer {
            beforeDeployment { MavenDeployment deployment ->
                signing {
                    fileTree( dir: file( "$buildDir/artifacts" ) ).each {
                        sign it
                        println "sign: " + it
                    }
                }
            }

            if (project.hasProperty("ossrhUsername") ){
                repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
                    authentication(userName: project["ossrhUsername"], password: project["ossrhPassword"])
                }
            }
         }
    }
}

Upvotes: 1

Related Questions