Adding BuckLibGenerator to autogenerate lib/BUCK
Change-Id: I7eab26f57d4f5886b1512b687fca75d684938d46
diff --git a/lib/BUCK b/lib/BUCK
index 78f7c75..c0e7ca5 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -1,4 +1,4 @@
-# ***** This file was auto-generated at Mon May 02 11:42:36 PDT 2016. Do not edit this file manually. *****
+# ***** This file was auto-generated at Wed May 04 19:19:10 PDT 2016. Do not edit this file manually. *****
osgi_feature_group(
name = 'COMPILE',
visibility = ['PUBLIC'],
@@ -187,9 +187,9 @@
remote_jar (
name = 'onos-atomix',
- out = 'atomix-1.0.onos-20160502.173651-190.jar',
- url = 'https://oss.sonatype.org/content/repositories/snapshots/org/onosproject/atomix/1.0.onos-SNAPSHOT/atomix-1.0.onos-20160502.173651-190.jar',
- sha1 = '763da0295d060271ae223db474dd024a7e84c629',
+ out = 'atomix-1.0.onos-20160505.013719-220.jar',
+ url = 'https://oss.sonatype.org/content/repositories/snapshots/org/onosproject/atomix/1.0.onos-SNAPSHOT/atomix-1.0.onos-20160505.013719-220.jar',
+ sha1 = '9dabad079e1fcd15f58cf995b84eda562b8de21e',
maven_coords = 'org.onosproject:atomix:1.0.onos-SNAPSHOT',
visibility = [ 'PUBLIC' ],
)
diff --git a/tools/build/libgen/BUCK b/tools/build/libgen/BUCK
new file mode 100644
index 0000000..60a1cb8
--- /dev/null
+++ b/tools/build/libgen/BUCK
@@ -0,0 +1,17 @@
+#FIXME build this dynamically
+
+URL = 'https://oss.sonatype.org/content/repositories/snapshots/org/onosproject/libgen/1.0-SNAPSHOT/libgen-1.0-20160505.022015-2.jar'
+SHA = 'fa29f6f5432587df65e55a7d0c99d1454577dcfd'
+
+prebuilt_jar(
+ name = 'libgen',
+ binary_jar = ':libgen-jar',
+ visibility = [ 'PUBLIC' ],
+)
+
+remote_file (
+ name = 'libgen-jar',
+ out = 'libgen.jar',
+ url = URL,
+ sha1 = SHA,
+)
\ No newline at end of file
diff --git a/tools/build/libgen/pom.xml b/tools/build/libgen/pom.xml
new file mode 100644
index 0000000..af3936f
--- /dev/null
+++ b/tools/build/libgen/pom.xml
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2016-present Open Networking Laboratory
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-base</artifactId>
+ <version>1</version>
+ <relativePath/>
+ </parent>
+
+ <groupId>org.onosproject</groupId>
+ <artifactId>libgen</artifactId>
+ <packaging>jar</packaging>
+ <version>1.0-SNAPSHOT</version>
+
+ <description>Buck third-party library generator</description>
+ <url>http://onosproject.org/</url>
+
+ <scm>
+ <connection>scm:git:https://gerrit.onosproject.org/onos</connection>
+ <developerConnection>scm:git:https://gerrit.onosproject.org/onos</developerConnection>
+ <url>http://gerrit.onosproject.org/</url>
+ </scm>
+
+ <licenses>
+ <license>
+ <name>Apache License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ </license>
+ </licenses>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ <version>2.7.0</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>2.7.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.aether</groupId>
+ <artifactId>aether-api</artifactId>
+ <version>1.1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.aether</groupId>
+ <artifactId>aether-util</artifactId>
+ <version>1.1.0</version>
+ </dependency>
+ <!--<dependency>-->
+ <!--<groupId>commons-configuration</groupId>-->
+ <!--<artifactId>commons-configuration</artifactId>-->
+ <!--<version>1.10</version>-->
+ <!--</dependency>-->
+ <!--<dependency>-->
+ <!--<groupId>commons-collections</groupId>-->
+ <!--<artifactId>commons-collections</artifactId>-->
+ <!--<version>3.2.2</version>-->
+ <!--</dependency>-->
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-aether-provider</artifactId>
+ <version>3.3.9</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.aether</groupId>
+ <artifactId>aether-connector-basic</artifactId>
+ <version>1.1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.aether</groupId>
+ <artifactId>aether-transport-file</artifactId>
+ <version>1.1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.aether</groupId>
+ <artifactId>aether-transport-http</artifactId>
+ <version>1.1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>1.6.2</version>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>2.4.2</version>
+ <configuration>
+ <transformers>
+ <transformer
+ implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+ <mainClass>org.onosproject.libgen.BuckLibGenerator</mainClass>
+ </transformer>
+ </transformers>
+ <filters>
+ <filter>
+ <artifact>*</artifact>
+ </filter>
+ </filters>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.10</version>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/tools/build/libgen/src/main/java/org/onosproject/libgen/AetherResolver.java b/tools/build/libgen/src/main/java/org/onosproject/libgen/AetherResolver.java
new file mode 100644
index 0000000..fbc3162
--- /dev/null
+++ b/tools/build/libgen/src/main/java/org/onosproject/libgen/AetherResolver.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.libgen;
+
+import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.collection.CollectRequest;
+import org.eclipse.aether.collection.CollectResult;
+import org.eclipse.aether.collection.DependencyCollectionException;
+import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.graph.DependencyFilter;
+import org.eclipse.aether.graph.DependencyNode;
+import org.eclipse.aether.impl.DefaultServiceLocator;
+import org.eclipse.aether.repository.LocalRepository;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.repository.RepositoryPolicy;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.ArtifactResult;
+import org.eclipse.aether.resolution.DependencyRequest;
+import org.eclipse.aether.resolution.VersionRangeRequest;
+import org.eclipse.aether.resolution.VersionRangeResolutionException;
+import org.eclipse.aether.resolution.VersionRangeResult;
+import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
+import org.eclipse.aether.spi.connector.transport.TransporterFactory;
+import org.eclipse.aether.transport.file.FileTransporterFactory;
+import org.eclipse.aether.transport.http.HttpTransporterFactory;
+import org.eclipse.aether.util.artifact.JavaScopes;
+import org.eclipse.aether.util.filter.DependencyFilterUtils;
+import org.eclipse.aether.version.Version;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.Reader;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+
+import static org.eclipse.aether.repository.RepositoryPolicy.CHECKSUM_POLICY_WARN;
+import static org.eclipse.aether.repository.RepositoryPolicy.UPDATE_POLICY_ALWAYS;
+
+/**
+ * Resolver capable of resolving Maven coordinates to a Maven artifact.
+ */
+public class AetherResolver {
+ private static final String CENTRAL_URL = "http://repo1.maven.org/maven2/";
+
+ private static RepositorySystem system;
+ private static RepositorySystemSession session;
+ private static final RemoteRepository CENTRAL =
+ new RemoteRepository.Builder("central", "default", CENTRAL_URL).build();
+
+ private final String repoUrl;
+
+ static {
+ DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
+ locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class );
+ locator.addService(TransporterFactory.class, FileTransporterFactory.class );
+ locator.addService(TransporterFactory.class, HttpTransporterFactory.class );
+
+ locator.setErrorHandler( new DefaultServiceLocator.ErrorHandler()
+ {
+ @Override
+ public void serviceCreationFailed( Class<?> type, Class<?> impl, Throwable exception )
+ {
+ exception.printStackTrace();
+ }
+ } );
+
+ AetherResolver.system = locator.getService( RepositorySystem.class );
+
+ DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
+
+ LocalRepository localRepo = new LocalRepository("target/local-repo" );
+ session.setLocalRepositoryManager( system.newLocalRepositoryManager( session, localRepo ) );
+
+ //session.setTransferListener( new ConsoleTransferListener() );
+ //session.setRepositoryListener( new ConsoleRepositoryListener() );
+ AetherResolver.session = session;
+ }
+
+ public static BuckArtifact getArtifact(String name, String uri, String repo) {
+ return new AetherResolver(repo).build(name, uri);
+ }
+
+ private AetherResolver(String repoUrl) {
+ this.repoUrl = repoUrl;
+ }
+
+ private BuckArtifact build(String name, String uri) {
+ uri = uri.replaceFirst("mvn:", "");
+ Artifact artifact = new DefaultArtifact(uri);
+ String originalVersion = artifact.getVersion();
+ try {
+ artifact = artifact.setVersion(newestVersion(artifact));
+ artifact = resolveArtifact(artifact);
+ String sha = getSha(artifact);
+ boolean osgiReady = isOsgiReady(artifact);
+
+ if (originalVersion.endsWith("-SNAPSHOT")) {
+ String url = String.format("%s/%s/%s/%s/%s-%s.%s",
+ repoUrl,
+ artifact.getGroupId().replace('.', '/'),
+ artifact.getArtifactId(),
+ originalVersion,
+ artifact.getArtifactId(),
+ artifact.getVersion(),
+ artifact.getExtension());
+ String mavenCoords = String.format("%s:%s:%s",
+ artifact.getGroupId(),
+ artifact.getArtifactId(),
+ originalVersion);
+ return BuckArtifact.getArtifact(name, url, sha, mavenCoords, osgiReady);
+ }
+ return BuckArtifact.getArtifact(name, artifact, sha, repoUrl, osgiReady);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Artifact resolveArtifact(Artifact artifact) throws Exception {
+ ArtifactRequest request = new ArtifactRequest();
+ request.setArtifact(artifact);
+ request.setRepositories(repositories());
+ ArtifactResult result = system.resolveArtifact(session, request);
+ return result.getArtifact();
+ }
+
+ private boolean isOsgiReady(Artifact artifact) throws Exception {
+ JarFile jar = new JarFile(artifact.getFile());
+ Attributes attrs = jar.getManifest().getMainAttributes();
+ return attrs.getValue("Bundle-SymbolicName") != null &&
+ attrs.getValue("Bundle-Version") != null;
+ }
+
+ private String getSha(Artifact artifact) throws Exception {
+ String directory = artifact.getFile().getParent();
+ String file = String.format("%s-%s.%s.sha1",
+ artifact.getArtifactId(),
+ artifact.getVersion(),
+ artifact.getExtension());
+ String shaPath = Paths.get(directory, file).toString();
+
+ try (Reader reader = new FileReader(shaPath)) {
+ return new BufferedReader(reader).readLine().trim().split(" ", 2)[0];
+ }
+ }
+
+ private String newestVersion(Artifact artifact) throws VersionRangeResolutionException {
+ VersionRangeRequest rangeRequest = new VersionRangeRequest();
+ rangeRequest.setArtifact(artifact);
+ rangeRequest.setRepositories(repositories());
+
+ VersionRangeResult rangeResult = system.resolveVersionRange(session, rangeRequest );
+
+ Version newestVersion = rangeResult.getHighestVersion();
+
+ return newestVersion.toString();
+ }
+
+ public List<RemoteRepository> repositories()
+ {
+ if (repoUrl != null && repoUrl.length() > 0) {
+ RepositoryPolicy policy = new RepositoryPolicy(true,
+ UPDATE_POLICY_ALWAYS,
+ CHECKSUM_POLICY_WARN);
+ RemoteRepository repository =
+ new RemoteRepository.Builder("temp", "default", repoUrl)
+ .setSnapshotPolicy(policy).build();
+ return Arrays.asList(CENTRAL, repository);
+ }
+
+ return Collections.singletonList(CENTRAL);
+ }
+}
diff --git a/tools/build/libgen/src/main/java/org/onosproject/libgen/BuckArtifact.java b/tools/build/libgen/src/main/java/org/onosproject/libgen/BuckArtifact.java
new file mode 100644
index 0000000..c9e9e19
--- /dev/null
+++ b/tools/build/libgen/src/main/java/org/onosproject/libgen/BuckArtifact.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.libgen;
+
+import org.eclipse.aether.artifact.Artifact;
+
+/**
+ * Representation of a remote artifact for Buck.
+ */
+public abstract class BuckArtifact {
+
+ private final String name;
+ private final String sha;
+ private final boolean osgiReady;
+
+ public static BuckArtifact getArtifact(String name, Artifact artifact, String sha, String repo, boolean osgiReady) {
+ return new MavenArtifact(name, artifact, sha, repo, osgiReady);
+ }
+ public static BuckArtifact getArtifact(String name, String url, String sha, String mavenCoords, boolean osgiReady) {
+ return new HTTPArtifact(name, url, sha, mavenCoords, osgiReady);
+ }
+ public static BuckArtifact getArtifact(String name, String url, String sha) {
+ return new HTTPArtifact(name, url, sha, null, true);
+ }
+
+ public BuckArtifact(String name, String sha, boolean osgiReady) {
+ this.name = name;
+ this.sha = sha;
+ this.osgiReady = osgiReady;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ abstract String fileName();
+
+ abstract String url();
+
+ private String jarTarget() {
+ return name != null ? name : fileName();
+ }
+
+ private boolean isPublic() {
+ return name != null;
+ }
+
+ boolean isOsgiReady() {
+ return osgiReady;
+ }
+
+ String mavenCoords() {
+ return null;
+ }
+
+ public String getBuckFragment() {
+ String visibility = isPublic() ? "[ 'PUBLIC' ]" : "[]";
+
+ boolean isJar = fileName().endsWith(".jar");
+ String output = (isJar ? "remote_jar" : "remote_file") + " (\n" +
+ " name = '%s',\n" + // jar target
+ " out = '%s',\n" + // jar file name
+ " url = '%s',\n" + // maven url
+ " sha1 = '%s',\n" + // artifact sha
+ ( isJar && mavenCoords() != null ?
+ " maven_coords = '"+ mavenCoords()+"',\n" : "" ) +
+ " visibility = %s,\n" +
+ ")\n\n";
+
+ return String.format(output, jarTarget(), fileName(), url(), sha, visibility);
+ }
+
+ private static class HTTPArtifact extends BuckArtifact {
+ private final String url;
+ private final String mavenCoords;
+
+ public HTTPArtifact(String name, String url, String sha, String mavenCoords, boolean osgiReady) {
+ super(name, sha, osgiReady);
+ this.url = url;
+ this.mavenCoords = mavenCoords;
+ }
+
+ @Override
+ String fileName() {
+ String[] parts = url.split("/");
+ return parts[parts.length - 1];
+ }
+
+ @Override
+ String mavenCoords() {
+ return mavenCoords;
+ }
+
+ @Override
+ String url() {
+ return url;
+ }
+ }
+
+ private static class MavenArtifact extends BuckArtifact {
+ private final Artifact artifact;
+ private final String repo;
+
+ private MavenArtifact(String name, Artifact artifact, String sha, String repo, boolean osgiReady) {
+ super(name, sha, osgiReady);
+ this.artifact = artifact;
+ this.repo = repo;
+ }
+
+ @Override
+ String url() {
+ //mvn:[repo:]groupId:artifactId:[extension:[classifier:]]:version
+ StringBuilder mvnUrl = new StringBuilder("mvn:");
+ if (repo != null && repo.length() > 0) {
+ mvnUrl.append(repo).append(':');
+ }
+ mvnUrl.append(artifact.getGroupId()).append(':')
+ .append(artifact.getArtifactId()).append(':')
+ .append(artifact.getExtension()).append(':');
+ if (artifact.getClassifier() != null && artifact.getClassifier().length() > 0) {
+ mvnUrl.append(artifact.getClassifier()).append(':');
+ }
+ mvnUrl.append(artifact.getVersion());
+ return mvnUrl.toString();
+ }
+
+ //FIXME get sources jars
+
+ @Override
+ String mavenCoords() {
+ String classifer = artifact.getClassifier();
+ if (!isOsgiReady()) {
+ classifer = "NON-OSGI" + classifer;
+ }
+
+ if ("jar".equals(artifact.getExtension().toLowerCase()) &&
+ classifer.length() == 0) {
+ // shorter form
+ return String.format("%s:%s:%s",
+ artifact.getGroupId(),
+ artifact.getArtifactId(),
+ artifact.getVersion());
+ }
+ return String.format("%s:%s:%s:%s:%s",
+ artifact.getGroupId(),
+ artifact.getArtifactId(),
+ artifact.getExtension(),
+ classifer,
+ artifact.getVersion());
+ }
+
+ @Override
+ String fileName() {
+ return String.format("%s-%s.%s",
+ artifact.getArtifactId(),
+ artifact.getVersion(),
+ artifact.getExtension());
+ }
+ }
+}
diff --git a/tools/build/libgen/src/main/java/org/onosproject/libgen/BuckLibGenerator.java b/tools/build/libgen/src/main/java/org/onosproject/libgen/BuckLibGenerator.java
new file mode 100644
index 0000000..d915ddd
--- /dev/null
+++ b/tools/build/libgen/src/main/java/org/onosproject/libgen/BuckLibGenerator.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.libgen;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Generates a BUCK file from a JSON file containing third-party library
+ * dependencies.
+ */
+public class BuckLibGenerator {
+
+// public static final String MAVEN_COORDS = "maven_coords";
+// public static final String COMPILE_ONLY = "compile_only";
+// public static final String RUNTIME_ONLY = "runtime_only";
+
+ private final ObjectNode jsonRoot;
+ private final List<BuckArtifact> artifacts = new ArrayList<>();
+ private final List<BuckLibrary> libraries = new ArrayList<>();
+
+ /**
+ * Main entry point.
+ *
+ * @param args command-line arguments; JSON input file and BUCK output file
+ */
+ public static void main(String[] args) throws Exception {
+ if (args.length < 2) {
+ System.err.println("Not enough args.\n\nUSAGE: <json file> <output>");
+ System.exit(5);
+ }
+
+ // Parse args
+ String jsonFilePath = args[0];
+ String outputBuckPath = args[1];
+
+ // Load and parse input JSON file
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
+ ObjectNode json = (ObjectNode) mapper.reader()
+ .readTree(new FileInputStream(jsonFilePath));
+
+ // Traverse dependencies and build a dependency graph (DAG)
+ BuckLibGenerator generator = new BuckLibGenerator(json).resolve();
+
+ // Write the output BUCK file
+ generator.write(outputBuckPath);
+ System.out.printf("\nFinish writing %s\n", outputBuckPath);
+ }
+
+ public BuckLibGenerator(ObjectNode root) {
+ this.jsonRoot = root;
+ }
+
+ private BuckArtifact parseArtifact(Map.Entry<String, JsonNode> entry) {
+ String name = entry.getKey();
+ JsonNode value = entry.getValue();
+ String uri;
+ String repo = null;
+ if (value.isTextual()) {
+ uri = value.asText();
+ } else if (value.isObject()) {
+ uri = value.get("uri").asText();
+ repo = value.get("repo").asText("");
+ } else {
+ throw new RuntimeException("Unknown element for name: " + name +
+ " of type: " + value.getNodeType());
+ }
+
+ System.out.print(name + " ");
+ System.out.flush();
+ BuckArtifact buckArtifact;
+ if (uri.startsWith("http")) {
+ String sha = getHttpSha(uri);
+ buckArtifact = BuckArtifact.getArtifact(name, uri, sha);
+ } else if (uri.startsWith("mvn")) {
+ uri = uri.replaceFirst("mvn:", "");
+// if (repo != null) {
+// System.out.println(name + " " + repo);
+// }
+ buckArtifact = AetherResolver.getArtifact(name, uri, repo);
+ } else {
+ throw new RuntimeException("Unsupported artifact uri: " + uri);
+ }
+ System.out.println(buckArtifact.url());
+ return buckArtifact;
+ }
+
+ private BuckLibrary parseLibrary(Map.Entry<String, JsonNode> entry) {
+ String libraryName = entry.getKey();
+ JsonNode list = entry.getValue();
+ if (list.size() == 0) {
+ throw new RuntimeException("Empty library: " + libraryName);
+ }
+
+ List<String> libraryTargets = new ArrayList<>(list.size());
+ list.forEach(node -> {
+ String name;
+ if (node.isObject()) {
+ name = node.get("name").asText();
+ } else if (node.isTextual()) {
+ name = node.asText();
+ } else {
+ throw new RuntimeException("Unknown node type: " + node.getNodeType());
+ }
+ if (!name.contains(":")) {
+ name = ':' + name;
+ }
+ libraryTargets.add(name);
+ });
+
+ return BuckLibrary.getLibrary(libraryName, libraryTargets);
+ }
+
+ public BuckLibGenerator resolve() {
+ jsonRoot.get("artifacts").fields().forEachRemaining(entry -> {
+ BuckArtifact buckArtifact = parseArtifact(entry);
+ artifacts.add(buckArtifact);
+// String artifactName = buckArtifact.name();
+// if (artifacts.putIfAbsent(artifactName, buckArtifact) != null) {
+// error("Duplicate artifact: %s", artifactName);
+// }
+ });
+
+ jsonRoot.get("libraries").fields().forEachRemaining(entry -> {
+ BuckLibrary library = parseLibrary(entry);
+ libraries.add(library);
+// String libraryName = library.name();
+// if (libraries.putIfAbsent(libraryName, library) != null) {
+// error("Duplicate library: %s", libraryName);
+// }
+ });
+
+ return this;
+ }
+
+ void write(String outputFilePath) {
+ File outputFile = new File(outputFilePath);
+ if (!outputFile.setWritable(true)) {
+ error("Failed to make %s to writeable.", outputFilePath);
+ }
+ try (PrintWriter writer = new PrintWriter(outputFile)) {
+ writer.write(String.format(
+ "# ***** This file was auto-generated at %s. Do not edit this file manually. *****\n",
+ new Date().toString()));
+ libraries.forEach(library -> writer.print(library.getBuckFragment()));
+ artifacts.forEach(artifact -> writer.print(artifact.getBuckFragment()));
+ writer.flush();
+ } catch (FileNotFoundException e) {
+ error("File not found: %s", outputFilePath);
+ }
+ if (!outputFile.setReadOnly()) {
+ error("Failed to set %s to read-only.", outputFilePath);
+ }
+ }
+
+ String getHttpSha(String url) {
+ //TODO look in buck-out/gen first
+ //FIXME need http download cache
+ try {
+ URLConnection connection = new URL(url).openConnection();
+ connection.connect();
+ InputStream stream = connection.getInputStream();
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+
+ byte[] buffer = new byte[8192];
+ int read;
+ while ((read = stream.read(buffer)) >= 0) {
+ md.update(buffer, 0, read);
+ }
+ StringBuilder result = new StringBuilder();
+ byte[] digest = md.digest();
+ for (byte b : digest) {
+ result.append(String.format("%02x", b));
+ }
+ return result.toString();
+ } catch (IOException | NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void error(String format, String... args) {
+ if (!format.endsWith("\n")) {
+ format += '\n';
+ }
+ System.err.printf(format, args);
+ System.exit(1);
+ }
+}
diff --git a/tools/build/libgen/src/main/java/org/onosproject/libgen/BuckLibrary.java b/tools/build/libgen/src/main/java/org/onosproject/libgen/BuckLibrary.java
new file mode 100644
index 0000000..1eaa978
--- /dev/null
+++ b/tools/build/libgen/src/main/java/org/onosproject/libgen/BuckLibrary.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.libgen;
+
+import org.eclipse.aether.artifact.Artifact;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Representation of a java library for Buck.
+ */
+public class BuckLibrary {
+
+ private final String name;
+ private final List<String> targets;
+
+ private final Set<Artifact> provided = new HashSet<>();
+ private final Set<Artifact> runtime = new HashSet<>();
+
+ public static BuckLibrary getLibrary(String libraryName, List<String> libraryTargets) {
+ return new BuckLibrary(libraryName, libraryTargets);
+ }
+
+ private BuckLibrary(String name, List<String> targets) {
+ this.name = name;
+ this.targets = targets;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public String getBuckFragment() {
+ StringBuilder output = new StringBuilder()
+ .append("osgi_feature_group(\n")
+ .append(String.format(" name = '%s',\n", name))
+ .append(" visibility = ['PUBLIC'],\n")
+ .append(" exported_deps = [");
+
+ targets.forEach(target -> output.append(String.format("\n '%s',", target)));
+ output.append("\n ],\n)\n\n");
+
+ return output.toString();
+ }
+}
\ No newline at end of file
diff --git a/tools/build/onos-lib-gen b/tools/build/onos-lib-gen
new file mode 100755
index 0000000..1bed9cf
--- /dev/null
+++ b/tools/build/onos-lib-gen
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+cd $(buck root 2>/dev/null)
+
+java -jar $(buck build //tools/build/libgen:libgen --show-output 2>/dev/null | tail -1 | cut -d' ' -f2) lib/deps.json lib/BUCK
diff --git a/tools/package/BUCK b/tools/package/BUCK
index 31896f3..c02b4c9 100644
--- a/tools/package/BUCK
+++ b/tools/package/BUCK
@@ -100,10 +100,11 @@
sources = [ '$(location :onos-features)', ]
sources += staged_repos + staged_apps
+import time
genrule(
name = 'onos-package',
out = 'onos.tar.gz',
- bash = '$(exe //buck-tools:onos-stage) $OUT $(location :onos-karaf) ' + ' '.join(sources),
+ bash = 'echo %s >/dev/null; $(exe //buck-tools:onos-stage) $OUT $(location :onos-karaf) ' % time.time() + ' '.join(sources),
visibility = [ 'PUBLIC' ],
)