Subclassing Probe doesn't work - qbs

I am trying to subclass Probe to clone custom repositories from the net before starting the build.
GitProbe:
import qbs
import qbs.File
import qbs.Process
Probe {
property string gitUrl
property string wd
property string name
property string dir: wd + "/" + name
configure: {
try {
if(File.directoryEntries(dir, File.AllEntries).length > 0){
File.remove(dir)
}
var gitProcess = Process()
gitProcess.setWorkingDirectory(wd)
gitProcess.exec("git", ["clone", gitUrl], true)
found = true
} catch(err) {
console.warn("GitProbe : could not clone repository " + gitUrl)
console.error("GitProbe : " + err)
found = false
}
}
}
I did put the GitProbe.qbs in dir/imports/ , and in my project I did qbsSearchPath: "path-to-dir", but qbs tell me when parsing the file Unexpected item type 'GitProbe'.

This is a known limitation: The search path needs to be set already when the current file is parsed. So the workaround is to reference your file from a Project item in another file and set the search path there. You might want to vote on https://bugreports.qt.io/browse/QBS-667.

Related

Dependency not resolved correctly when Product (CodeGenerator) used in Rule ([asd] -> [cpp])

when using a Rule inside a Module with a Dependency to a Product, a FileTagger breaks the resolution of dependencies in qbs.
We have a CodeGenerator in our project which is build by the project itself.
This CodeGenerator generates C++-Classes from *.asd-Files.
A Product called "Core" uses that CodeGenerator to generate Classes from Core.asd Files.
I am not sure if this is a bug in qbs, but since qbs 1.8 this part of our project does not work anymore.
I created a small test project that illustrates that problem:
RuleUsesProduct.qbs
import qbs
Project {
minimumQbsVersion: "1.8.0"
references: [
"Core/Core.qbs",
"CodeGenerator/CodeGenerator.qbs"
]
qbsSearchPaths: "QBS"
}
Core.qbs
import qbs
CppApplication {
Depends { name: "Qt.core" }
cpp.cxxLanguageVersion: "c++11"
cpp.defines: [
]
consoleApplication: true
files: [
"main.cpp",
"core.asd"
]
Depends{ name:"CodeGenerator"}
Depends{ name:"CodeGeneration"}
Group { // Properties for the produced executable
fileTagsFilter: product.type
qbs.install: true
}
}
Db2cppModule.qbs
This is indirectly included via the qbsSearchPath from RuleUsesProductTest.qbs
import qbs 1.0
import qbs.Environment
import qbs.FileInfo
import qbs.TextFile
import qbs.Process
import qbs.File
Module {
FileTagger {
patterns: ["*.asd"]
fileTags: ["asd"]
}
Rule {
id: dbRule
inputs: ["asd"]
inputsFromDependencies: ["application"]
multiplex: true
outputFileTags: ["cpp", "hpp"]
outputArtifacts: {
// dummy code that should call the CodeGenerator.exe with some parameters...
var process = new Process();
console.warn("# " + inputs["application"][0].filePath)
var cmdExp = "" + inputs["application"][0].filePath;
process.exec(cmdExp, [], false);
return []
}
prepare: {
console.warn("*" + inputs["application"][0].filePath)
var cmdExp = "" + inputs["application"][0].filePath;
var cmd = new Command(cmdExp, []);
return cmd
}
}
}
CodeGenerator.qbs
import qbs
CppApplication {
Depends { name: "Qt.core" }
cpp.cxxLanguageVersion: "c++11"
cpp.defines: [
]
consoleApplication: true
files: [
"codegenerator.cpp"
]
Group { // Properties for the produced executable
fileTagsFilter: product.type
qbs.install: true
}
}
Any help is much appreciated!
Qbs knows two types of rules: Multiplex and non-multiplex ones. Details can be found here: https://doc.qt.io/qbs/rule-item.html.
The important point for you is that non-multiplex rules invoke their prepare script once for every input. This means that in your example, the prepare script runs twice: Once for the asd input and once for the application input. The respective other inputs are not visible. This does not fit your use case, because you want to see both inputs at the same time. Therefore, you need to make your rule a multiplex rule:
multiplex: true
In the prepare script, you need to create one command for every input of type asd (unless your generator can take several inputs at once).
Rule of thumb (no pun intended): If your rule declares more than one input tag, it probably should be a multiplex rule.

Saving screenshots with protractor

I'm attempting to save a screenshot using a generic method in protractor. Two features, it creates the folder if it does not exist and it saves the file (with certain conditions).
export function WriteScreenShot(data: string, filename: string) {
let datetime = moment().format('YYYYMMDD-hhmmss');
filename = `../../../test-reports/${filename}.${datetime}.png`;
let path =filename.substring(0, filename.lastIndexOf('/'));
if (!fs.existsSync(path)) {
fs.mkdirSync(path);
}
let stream = fs.createWriteStream(filename);
stream.write(new Buffer(data, 'base64'));
stream.end();
}
This can be used by calling browser.takeScreenshot().then(png => WriteScreenShot(png, 'login/login-page')); Using this example call, a file will be created, I assumed, in the path relative where my WriteScreenShot method's file resides. But that does not appear to be the case.
For example, when I run my spec test in the spec's folder, the image gets saved in the correct place. But if I run it at the project root, an error is capture. Obviously, this has to do with my relative path reference. How do I capture the project's root directory and build from that so that I can run the test from any directory?
This is a classical directory access error. Let me just explain what is happening to your code -
let path =filename.substring(0, filename.lastIndexOf('/'));
The above line outputs to ../../../test-reports
fs.existsSync checks whether thispath exists or not -
case 1 :(postive flow) Your spec folder is in the same current working directory in which you are trying to create reports folder. When you run your test, the path exists, it generates the test-reports directory & screenshots and your code works fine.
case 2:(negative flow) When you try to run it from the root directory which is the current working directory now, fs.existsSync tries to check the path & the reports folder inside it. If it doesn't exist , fs.mkdirSync tries to create your directories but it would fail as it cannot create multiple directories.
You should be using native path module of nodejs to extract the path instead of using file substring and the mkdirp external module for creating multiple directories.
import * as path from 'path';
let {mkdirp} = require('mkdirp'); // npm i -D mkdirp
export function WriteScreenShot(data: string, filename: string) {
let datetime = moment().format('YYYYMMDD-hhmmss');
filename = `../../../test-reports/${filename}.${datetime}.png`;
let filePath = path.dirname(filename); // output: '../../..' (relative path)
// or
let filePath = path.resolve(__dirname); // output: 'your_root_dir_path' (absolute path)
// or
let filePath = path.resolve('.'); // output: 'your_root_dir_path' (absolute path)
if (!fs.existsSync(filePath )) {
mkdirp.sync(filePath); // creates multiple folders if they don't exist
}
let stream = fs.createWriteStream(filename);
stream.write(new Buffer(data, 'base64'));
stream.end();
}
If you are curious to know the difference btw mkdir & mkdir-p please read this SO thread.

How do I get the file/folder path using Apache Commons net FTPS Client

I am using Apache commons ftps client to connect to an ftps server. I have the remote file path which is a directory. This directory contains a tree of sub-directories and files. I want to get the path for each file or folder. Is there any way I can get this property? Or if there is any way I could get the parent folder path, I could concatenate the file name to it.
I am currently using below function to get path and size of all files under a certain directory. It gets all the file in current directory and check if it is a directory or file. If it is a directory call recursively until end of the tree, if it is a file save the path and size. You may not need these "map" things you can edit according to your needs.
Usage:
getServerFiles(ftp,"") // start from root
or
getServerFiles(ftp,"directory_name") // start from given directory
Implementation:
def getServerFiles(ftp: FTPClient, dir: String): Map[String, Double] = {
var fileList = Array[FTPFile]()
var base = ""
if (dir == "") {
fileList = ftp.listFiles
} else {
base = dir + "/"
fileList = ftp.listFiles(dir)
}
fileList.flatMap {
x => if (x.isDirectory) {
getServerFiles(ftp, base + x.getName)
} else {
Map[String, Double](base + x.getName -> x.getSize)
}
}.toMap
}

How can I get the project path in Scala?

I'm trying to read some files from my Scala project, and if I use: java.io.File(".").getCanonicalPath() I find that my current directory is far away from them (exactly where I have installed Scala Eclipse). So how can I change the current directory to the root of my project, or get the path to my project? I really don't want to have an absolute path to my input files.
val PATH = raw"E:\lang\scala\progfun\src\examples\"
def printFileContents(filename: String) {
try {
println("\n" + PATH + filename)
io.Source.fromFile(PATH + filename).getLines.foreach(println)
} catch {
case _:Throwable => println("filename " + filename + " not found")
}
}
val filenames = List("random.txt", "a.txt", "b.txt", "c.txt")
filenames foreach printFileContents
Add your files to src/main/resources/<packageName> where <packageName> is your class package.
Change the line val PATH = getClass.getResource("").getPath
new File(".").getCanonicalPath
will give you the base-path you need
Another workaround is to put the path you need in an user environmental variable, and call it with sys.env (returns exception if failure) or System.getenv (returns null if failure), for example val PATH = sys.env("ScalaProjectPath") but the problem is that if you move the project you have to update the variable, which I didn't want.

gwt getting abosulte path on server side

Iam trying since 1 hour to get the absolute path of a file ony server side:
String path = request.getRequestURL();
JasperCompileManager.compileReportToFile(path+"/test.jrxml",path+"/test.jasper");
this didnt work my expection is :
not found : http\12.0.0.13:8080]\test\test.jrxml wrong syntax in dataname...etc
Try this one in your RemoteServiceServlet class to get the absolute path of any resources placed under war directory that will be actually the path of server directory when deployed on server.
String pngFullPath = this.getThreadLocalRequest().getSession().getServletContext()
.getRealPath("images/1.png");
System.out.println(pngFullPath);
String icoFullPath = this.getThreadLocalRequest().getSession().getServletContext()
.getRealPath("favicon.ico");
System.out.println(icoFullPath);
output:
D:\Workspace\GWTProject\war\images\1.png
D:\Workspace\GWTProject\war\favicon.ico
Now change it as per the placement of test.jrxml file in your project.
here is the project structure:
This is the method I use:
public static String getServerBase(HttpServletRequest req)
{
String scheme = req.getScheme(); // http
String serverName = req.getServerName(); // sub.domain.ac.uk
int serverPort = req.getServerPort(); // 80
String contextPath = req.getContextPath(); // /MyApp
return scheme + "://" + serverName + ":" + serverPort + contextPath;
}
Then simply append your file name.