-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8c499d9
commit 114ffd5
Showing
13 changed files
with
450 additions
and
18 deletions.
There are no files selected for viewing
39 changes: 39 additions & 0 deletions
39
snap-studio-agent/src/main/java/org/snapscript/studio/agent/local/LocalJarProcess.java
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package org.snapscript.studio.agent.local; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.jar.Attributes; | ||
import java.util.jar.Manifest; | ||
|
||
import org.snapscript.core.module.Path; | ||
import org.snapscript.studio.agent.cli.CommandLine; | ||
import org.snapscript.studio.agent.cli.CommandLineBuilder; | ||
|
||
public class LocalJarProcess { | ||
|
||
public static final String MAIN_SCRIPT = "Main-Script"; | ||
|
||
public static void main(String[] arguments) throws Exception { | ||
CommandLineBuilder builder = LocalOption.getBuilder(); | ||
CommandLine line = builder.build(arguments); | ||
LocalCommandLine local = new LocalCommandLine(line); | ||
Path path = local.getScript(); | ||
|
||
if(path == null) { | ||
String[] empty = new String[]{}; | ||
List<String> expanded = new ArrayList<String>(); | ||
Attributes.Name key = new Attributes.Name(MAIN_SCRIPT); | ||
|
||
Manifest manifest = LocalManifestReader.readManifest(); | ||
String script = (String)manifest.getMainAttributes().get(key); | ||
|
||
for(String argument : arguments) { | ||
expanded.add(argument); | ||
} | ||
String argument = String.format("--%s=%s", LocalOption.SCRIPT.name, script); | ||
expanded.add(argument); | ||
arguments = expanded.toArray(empty); | ||
} | ||
LocalProcess.main(arguments); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
snap-studio-agent/src/main/java/org/snapscript/studio/agent/local/LocalManifestReader.java
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.snapscript.studio.agent.local; | ||
|
||
import java.io.InputStream; | ||
import java.util.jar.Manifest; | ||
|
||
public class LocalManifestReader { | ||
|
||
public static Manifest readManifest() { | ||
try { | ||
InputStream resource = LocalManifestReader.class.getResourceAsStream("META-INF/MANIFEST.MF"); | ||
|
||
if(resource == null) { | ||
resource = LocalManifestReader.class.getResourceAsStream("/META-INF/MANIFEST.MF"); | ||
} | ||
return new Manifest(resource); | ||
} catch(Exception e) { | ||
throw new IllegalStateException("Could not read manifest file", e); | ||
} | ||
} | ||
} |
273 changes: 273 additions & 0 deletions
273
snap-studio-project/src/main/java/org/snapscript/studio/project/ArchiveBuilder.java
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,273 @@ | ||
package org.snapscript.studio.project; | ||
|
||
import static org.springframework.core.io.support.ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX; | ||
|
||
import java.io.File; | ||
import java.io.FileOutputStream; | ||
import java.io.InputStream; | ||
import java.io.OutputStream; | ||
import java.util.Enumeration; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Map.Entry; | ||
import java.util.Set; | ||
import java.util.concurrent.ExecutorService; | ||
import java.util.concurrent.Executors; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.jar.Attributes; | ||
import java.util.jar.JarEntry; | ||
import java.util.jar.JarFile; | ||
import java.util.jar.JarOutputStream; | ||
import java.util.jar.Manifest; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
|
||
import org.apache.commons.io.FileUtils; | ||
import org.apache.commons.io.IOUtils; | ||
import org.codehaus.plexus.util.StringUtils; | ||
import org.snapscript.core.type.extend.FileExtension; | ||
import org.snapscript.studio.agent.local.LocalJarProcess; | ||
import org.snapscript.studio.agent.local.LocalProcess; | ||
import org.snapscript.studio.project.generate.ClassPathConfigFile; | ||
import org.snapscript.studio.project.generate.ClassPathFileGenerator; | ||
import org.springframework.core.io.Resource; | ||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver; | ||
|
||
@Slf4j | ||
public class ArchiveBuilder { | ||
|
||
private static final ArchivePath[] RUNTIME_PACKAGES = new ArchivePath[]{ | ||
new ArchivePath("org/snapscript/studio/agent", true), | ||
new ArchivePath("org/snapscript/compile", true), | ||
new ArchivePath("org/snapscript/common", true), | ||
new ArchivePath("org/snapscript/platform", true), | ||
new ArchivePath("org/snapscript/cglib", true), | ||
new ArchivePath("org/snapscript/asm", true), | ||
new ArchivePath("org/snapscript/dx", true), | ||
new ArchivePath("org/snapscript/parse", true), | ||
new ArchivePath("org/snapscript/core", true), | ||
new ArchivePath("org/snapscript/tree", true), | ||
new ArchivePath("import.txt", false), | ||
new ArchivePath("grammar.txt", false) | ||
}; | ||
|
||
private final PathMatchingResourcePatternResolver resolver; | ||
private final ClassPathFileGenerator generator; | ||
private final FileExtension extension; | ||
private final ProjectContext context; | ||
private final Project project; | ||
|
||
public ArchiveBuilder(Project project, ProjectContext context) { | ||
this.resolver = new PathMatchingResourcePatternResolver(); | ||
this.generator = new ClassPathFileGenerator(); | ||
this.extension = new FileExtension(); | ||
this.project = project; | ||
this.context = context; | ||
} | ||
|
||
public File exportArchive(String mainScript) { | ||
String name = project.getProjectName(); | ||
String tempDir = System.getProperty("java.io.tmpdir"); | ||
|
||
try { | ||
File destDir = new File(tempDir, name); | ||
File outputFile = new File(tempDir, name + ".jar"); | ||
|
||
collectResources(destDir); | ||
extractRuntime(destDir); | ||
extractClassPath(destDir); | ||
archiveDirectory(destDir, outputFile, mainScript); | ||
|
||
return outputFile; | ||
}catch(Exception e) { | ||
log.info("Could not export {}", name); | ||
throw new IllegalStateException("Could not export " + name, e); | ||
} | ||
} | ||
|
||
private void archiveDirectory(File sourceDir, File outputFile, String mainScript) throws Exception { | ||
Manifest manifest = new Manifest(); | ||
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); | ||
|
||
if(!StringUtils.isBlank(mainScript)) { | ||
Attributes.Name mainScriptKey = new Attributes.Name(LocalJarProcess.MAIN_SCRIPT); | ||
|
||
manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, LocalJarProcess.class.getName()); | ||
manifest.getMainAttributes().put(mainScriptKey, mainScript); | ||
} else { | ||
manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, LocalProcess.class.getName()); | ||
} | ||
OutputStream stream = new FileOutputStream(outputFile); | ||
JarOutputStream out = new JarOutputStream(stream, manifest); | ||
Set<String> done = new HashSet<String>(); | ||
|
||
try { | ||
List<File> files = extension.findFiles(sourceDir, ".*"); | ||
String sourcePath = sourceDir.getCanonicalPath(); | ||
int length = sourcePath.length(); | ||
|
||
for(File entry : files) { | ||
if(entry.isFile()) { | ||
String entryPath = entry.getCanonicalPath(); | ||
String relativePath = entryPath.substring(length).replace(File.separatorChar, '/'); | ||
|
||
if(done.add(relativePath) && !relativePath.endsWith("MANIFEST.MF")) { | ||
if(relativePath.startsWith("/")) { | ||
relativePath = relativePath.substring(1); // /org/domain/Type.class -> org/domain/Type.class | ||
} | ||
JarEntry jarEntry = new JarEntry(relativePath); | ||
byte[] data = FileUtils.readFileToByteArray(entry); | ||
|
||
log.info("Compressing {}", relativePath); | ||
out.putNextEntry(jarEntry); | ||
out.write(data); | ||
} | ||
} | ||
} | ||
} finally { | ||
out.close(); | ||
stream.close(); | ||
} | ||
} | ||
|
||
private void collectResources(File destDir) throws Exception { | ||
Map<String, File> files = context.getFiles(); | ||
Set<Entry<String, File>> entries = files.entrySet(); | ||
|
||
for(Entry<String, File> entry : entries) { | ||
String path = entry.getKey(); | ||
File file = entry.getValue(); | ||
|
||
if(file.isFile()) { | ||
byte[] content = FileUtils.readFileToByteArray(file); | ||
|
||
try { | ||
File outputFile = new File(destDir, path); | ||
|
||
if(!outputFile.getParentFile().exists()) { | ||
outputFile.getParentFile().mkdirs(); | ||
} | ||
log.info("Archiving {}", path); | ||
FileUtils.writeByteArrayToFile(outputFile, content); | ||
} catch(Exception e) { | ||
log.info("Could not collect {}", path); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void extractRuntime(File destDir) throws Exception{ | ||
for(ArchivePath path : RUNTIME_PACKAGES) { | ||
String prefix = path.getPath(); | ||
String pattern = path.getPattern(); | ||
Resource[] resources = resolver.getResources(CLASSPATH_ALL_URL_PREFIX + pattern); | ||
|
||
for(Resource resource : resources) { | ||
String target = resource.getURI().toString(); | ||
int index = target.indexOf(prefix); | ||
|
||
if(index != -1) { | ||
String relativePath = target.substring(index); | ||
File file = new File(destDir, relativePath); | ||
|
||
if(!file.getParentFile().exists()) { | ||
file.getParentFile().mkdirs(); | ||
} | ||
InputStream input = resource.getInputStream(); | ||
|
||
try { | ||
log.info("Archiving {}", relativePath); | ||
byte[] data = IOUtils.toByteArray(input); | ||
FileUtils.writeByteArrayToFile(file, data); | ||
}finally { | ||
input.close(); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void extractClassPath(File destDir) throws Exception{ | ||
File file = generator.getConfigFilePath(project); | ||
String content = FileUtils.readFileToString(file); | ||
ClassPathConfigFile configFile = generator.parseConfig(project, content); | ||
List<File> files = configFile.getFiles(); | ||
|
||
extractClassPath(destDir, files); | ||
} | ||
|
||
private void extractClassPath(final File destDir, final List<File> files) throws Exception { | ||
int threads = Runtime.getRuntime().availableProcessors(); | ||
ExecutorService executor = Executors.newFixedThreadPool(threads); | ||
|
||
for(File file : files) { | ||
if(file.isFile() && file.getName().endsWith(".jar")) { | ||
ArchiveJarExtractor extractor = new ArchiveJarExtractor(destDir, file); | ||
executor.execute(extractor); | ||
} | ||
} | ||
executor.shutdown(); | ||
executor.awaitTermination(1, TimeUnit.HOURS); | ||
} | ||
|
||
@AllArgsConstructor | ||
private static class ArchiveJarExtractor implements Runnable { | ||
|
||
private final File destDir; | ||
private final File file; | ||
|
||
@Override | ||
public void run() { | ||
try { | ||
JarFile jarfile = new JarFile(file); // jar file path(here sqljdbc4.jar) | ||
Enumeration<JarEntry> jarEntries = jarfile.entries(); | ||
|
||
while (jarEntries.hasMoreElements()) { | ||
JarEntry jarEntry = jarEntries.nextElement(); | ||
String fileName = jarEntry.getName(); | ||
File outputPath = new File(destDir, fileName); | ||
|
||
if (!outputPath.exists()) { | ||
outputPath.getParentFile().mkdirs(); | ||
} | ||
if (jarEntry.isDirectory()) { | ||
continue; | ||
} | ||
InputStream sourceFile = jarfile.getInputStream(jarEntry); | ||
FileOutputStream outputFile = new FileOutputStream(outputPath); | ||
|
||
try { | ||
log.info("Archiving {}", fileName); | ||
IOUtils.copy(sourceFile, outputFile); | ||
}finally { | ||
outputFile.close(); | ||
sourceFile.close(); | ||
} | ||
} | ||
jarfile.close(); | ||
} catch(Exception e) { | ||
log.info("Could not extract {}", file); | ||
} | ||
} | ||
} | ||
|
||
@AllArgsConstructor | ||
private static class ArchivePath { | ||
|
||
private final String prefix; | ||
private final boolean classes; | ||
|
||
public String getPattern(){ | ||
if(classes) { | ||
return prefix + "/**/*.class"; | ||
} | ||
return prefix; | ||
} | ||
|
||
public String getPath(){ | ||
return prefix; | ||
} | ||
} | ||
} |
This file contains 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
Oops, something went wrong.