Get the project path/output path during Postsharp compile time - postsharp

Is it possible to find out the project folder/project file or output path of the assembly during compile time in Postsharp, i.e. during CompileTimeInitialize for example, when the assembly is being built?

You can find out the path to the current project file by evaluating the 'MSBuildProjectFullPath' property during compile time:
public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
{
string projectPath =
PostSharpEnvironment.CurrentProject
.EvaluateExpression("{$MSBuildProjectFullPath}");
}
The list of some other PostSharp properties can be found on this documentation page.

Related

Could not find main method from given launch configuration

I've a simple Java project that works when I execute it at Eclipse environment. But when I try to export it to a Runnable Jar, I get the following error:
JAR export finished with warnings. See details for additional information.
Exported with compile warnings: JavaSwing/src.main.java/com/cansoft/GUIProgram.java
Exported with compile warnings: JavaSwing/src.main.java/com/util/Util.java
Jar export finished with problems. See details for additional information.
Could not find main method from given launch configuration.
I read other posts which suggest to create a MANIFEST.MF file specifying the main-class which I did. It is placed at MyProjectFolder/META-INF/MANIFEST.MF and it contains the following information:
Manifest-Version: 1.0
Class-Path: resources
main-class: com.cansoft.GUIProgram
My main class is as follows:
public class GUIProgram {
private JFrame folderCreationSubappFrame;
private Color color;
private String home;
private final static Logger LOG_MONITOR = Logger.getLogger("com.cansoft");
public static void main(String[] args) {
try {
new GUIProgram();
} catch (Exception e) {
LOG_MONITOR.log(Level.INFO,e.getMessage());
}
}
public GUIProgram() throws InterruptedException, SecurityException, IOException {
home = System.getProperty("user.home") + File.separator + "Documents";
startLogSystem();
if(isFirstRun()) {
showWelcomeFrame();
} else {
initialize();
}
} .... More and more code
Does anybody know what am I missing? Any help much appreciated.
Thank you.
It is not enough to create the manifest file, you need to explicitly choose it in the Eclipse jar export dialog.
Answer to Comment
If you use "runnable jar", make sure that you chose the correct launch configuration and that the launch configuration successfully runs when chosing "Run As" -> "Run Configurations" -> "Java Application" -> Your Configuration -> "Run"
I finally find out where the problem was, it was quite simple btw. I had created my GUIProgram within a src.main.java package, but that package was created (my bad) as resources instead of folders, so Eclipse was smart enought to run it but when trying to generate the JAR which expected a correct java project structure, it was failing because truly there were not GUIProgram java class at src path (src was not folder type but resources).
Hope I succeed explaining.

Loading a NuGet assembly in T4 Template

I need to reference a Type in one of the assemblies referenced by the project containing my Visual Studio T4 template. However, the referenced assembly is installed from a NuGet package. As that Nuget reference evolves, so will the path that NuGet places it in within my solution's packages folder. For example, suppose my NuGet package is:
Facade.Contract.1.0.1-alpha
Then the relative path to it from my project is:
..\packages\Facade.Contract.1.0.1-alpha\lib\net4\Facade.Contract.dll
If the prerelease is updated to beta, that path will change. When the package is released, the path will change. And every time the path changes, the assembly line in my *.tt file is out of date:
<## assembly name="..\packages\Facade.Contract.1.0.1-alpha\lib\net4\Facade.Contract.dll" #>
I don't think there's a way to accomplish this directly with the assembly directive; however, I'm open to some crazy ideas. Could I load the assembly myself into the current, or a subordinate or reflection-only AppDomain?
I think I could, but I'm not sure how to go about dynamically discovering the path to the referenced assembly in the project's references using T4 logic.
Any ideas?
I've found a solution using VSLangProject as suggested by this article: http://t4-editor.tangible-engineering.com/blog/add-references-to-visual-studio-project-from-t4-template.html
Given a string serviceContractReferenceAssembly a to identify the name of the reference assembly in my containing project, and serviceContractReferenceType to identify the type within that assembly, the following worked:
var templateItem = dte.Solution.FindProjectItem(this.Host.TemplateFile);
var project = templateItem.ContainingProject;
var vsProject = project.Object as VSLangProj.VSProject;
foreach(var referenceObj in vsProject.References)
{
var reference = (VSLangProj.Reference)referenceObj;
if(reference.Name != serviceContractReferenceAssembly) continue;
var serviceContractAssembly = Assembly.LoadFile(reference.Path);
var serviceContractType = serviceContractAssembly.GetType(serviceContractReferenceType);
// Do something with it here
}
The Nuget team has made an extension available that allows you some control over the packages in a solution/project. So if you have control over the environment and can be sure everyone has this installed you might be able to search for the installed packages and then dynamically load them during your T4 execution. Since these Nuget assemblies are already complied and not part of your solution/project I would think using the standard Assembly.Load would work but you would need to test that.

Intellij IDEA - Output path ...\project\target\idea-classes intersects with a source root. Only files that were created by build will be cleaned

Using Intellij IDEA with Scala plugin.
When doing a Build -> Rebuild Project I get the following make warnings:
Output path ProjectRootFolder\project\target\idea-test-classes intersects with a source root. Only files that were created by build will be cleaned.
Output path ProjectRootFolder\project\target\idea-classes intersects with a source root. Only files that were created by build will be cleaned.
The project was generated with SBT gen-idea plugin.
The two output paths mentioned in the warnings are set as output path and test output path for the build module of the project under Project Structure -> Modules -> ProjectName-build -> Paths -> Use module compile output path.
Looking at the Sources tab for both the ProjectName module and ProjectName-build modules I saw that there is no place where ProjectRootFolder\project\target was marked as Source.
It seems the warnings were caused by the fact that the project and . folders were marked as Sources in the ProjectName-build module.
Since the SBT build module is not needed when using IDEA to build the project, one solution would be to generate the IDEA project without that module:
sbt gen-idea no-sbt-build-module
More details here: https://github.com/mpeltonen/sbt-idea/issues/180
UPDATE
Removing the build module is actually problematic since the build.scala file will show a lot of warnings because the required libraries would be missing.
A solution would be to unmark . and project from being Sources of the build module, which is also troublesome since it would need to be done after each gen-idea.
A better solution would be to use sbt to build the project instead of make. To achieve that remove the make before launch step in the IDEA run configuration and add a SBT products step instead.
I get the same warning and it didn't cause any problems so far.
Judging by this code it seems that they simply delete only files generated by IDE, otherwise they would want to delete everything in target directory. They are playing safe by checking if there could be any source files there:
// check that output and source roots are not overlapping
final List<File> filesToDelete = new ArrayList<File>();
for (Map.Entry<File, Collection<BuildTarget<?>>> entry : rootsToDelete.entrySet()) {
context.checkCanceled();
boolean okToDelete = true;
final File outputRoot = entry.getKey();
if (JpsPathUtil.isUnder(allSourceRoots, outputRoot)) {
okToDelete = false;
}
else {
final Set<File> _outRoot = Collections.singleton(outputRoot);
for (File srcRoot : allSourceRoots) {
if (JpsPathUtil.isUnder(_outRoot, srcRoot)) {
okToDelete = false;
break;
}
}
}
if (okToDelete) {
// do not delete output root itself to avoid lots of unnecessary "roots_changed" events in IDEA
final File[] children = outputRoot.listFiles();
if (children != null) {
filesToDelete.addAll(Arrays.asList(children));
}
else if (outputRoot.isFile()) {
filesToDelete.add(outputRoot);
}
}
else {
context.processMessage(new CompilerMessage(
"", BuildMessage.Kind.WARNING, "Output path " + outputRoot.getPath() + " intersects with a source root. Only files that were created by build will be cleaned.")
);
// clean only those files we are aware of
for (BuildTarget<?> target : entry.getValue()) {
clearOutputFiles(context, target);
}
}
}

Eclipse how to reference file in a different src under the same project

My current setup in eclipse is like this:
trunk
--working/src
--resources
I have a java file inside a package under working/src and I am trying to retrieve a file in the resources. The path I am using is "../resources/file.txt". However I am getting an error saying that the file does not exist.
Any help would be appreciated thanks!
Considering your structure
I have package like
trunk
working/src/FileRead.java
resources/name list.txt
Following Code might solve your problem
package working.src;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
public class FileRead {
public FileRead() {
URL url = getClass().getResource("/resources/name list.txt");
try {
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String nameList;
while ((nameList = in.readLine()) != null) {
System.out.println(nameList);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new FileRead();
}
}
Files will be referenced relative to your project path, so use "resources/file.txt" to reference the file.
However, if you want the file to be accessible when you export the program as a JAR, the path "resources/file.txt" must exist relative to your JAR.
It depends on how you have specified your Java Build Path inside eclipse. I have tested two setups with different results:
Define the directory working/src only as build path. You can get the information what is in your build path through: Select project > Properties > Java Build Path > Tab Source. There are all source folders listed. You see there that there is a default output folder defined. All resources that are contained in a build path are copied to the default output folder, and are then available for the eclipse classes there. You can check that in the resource perspective in your bin folder if the resource is copied there. In this setup, only the classes are generated, resources are not copied (and therefore not found).
Define the directory working/src and resources as build path. Then the resource is copied and may then found by the path "file.txt"
So eclipse has a simple build process included and hides that from the developer, but it is a build process nonetheless.

Changing sbt project's directory layout

According to sbt tutorial on changing paths I'm trying to change "target" output directory to "someother"
override def outputDirectoryName = "someother"
Everything goes fine except one: sbt automatically creates target directory with ".history" file inside. Why sbt does this when it supposed do create only "someother" dir ? I tryied to override all methods that are inherited from BasicProjectPaths (I use sbt.DefaultProject as superclass of my project descriptor)
override def mainCompilePath = ...
override def testCompilePath = ...
...
But sbt creates "target" folder in spite of paths overriding.
It certainly seems that it should use the overridden outputDirectoryName in trunk...
/** The path to the file that provides persistence for history. */
def historyPath: Option[Path] = Some(outputRootPath / ".history")
def outputPath = crossPath(outputRootPath)
def outputRootPath: Path = outputDirectoryName
def outputDirectoryName = DefaultOutputDirectoryName
(from SBT's current trunk).
It may have been different in a previous version. Have you considered raising a new bug?
In sbt 0.13.5, I found a way to change the target folder by just re-assigning target in the build.sbt file:
target := file("someotherParent") / "someotherSubdir"
This only modifies the directory for the built classes and artifacts, however, the .history file is always in the project root directory.
Unfortunately, some other plugins (xsbt-web-plugin) seem to have problems with that - running the webapp via SBT console produced weird errors, when I switched back to the standard directory layout, these problems disappeared.
A better way to achieve my goals (of all JARS in one directory, whose names contains the JAVA-VM-version) seems to be to specify an appropriate target for publishing - there are less restrictions on "sbt publish", and other plugins are not disturbed by a different directory layout.