Qbs: install files preserving hierarchy - qbs

I have directory with files in subdirectories to be deployed with my application (qml plugins). The trouble is: if I try to install dirs:
Group {
name: "somegroup"
files: ["mysrc/dir"]
qbs.install: true
qbs.installDir: "mybuild"
}
I get a "Not recursively copying directory 'mysrc/dir' into target directory 'mybuild'. Install the individual file artifacts instead." error.
If I try to install files:
Group {
name: "somegroup"
files: ["mysrc/dir/**/*"]
qbs.install: true
qbs.installDir: "mybuild"
}
Then all of those files go into same directory ignoring hierarchy (and cannot be installed, because some of them share name).
Solution with multiple groups is too verbose either.
Is there a way to install directory with files, recursively, preserving hierarchy?

See the qbs.installSourceBase property; that's exactly what it is for.

example usage:
Group {
name: "qt_qml_plugins"
prefix: Qt.core.pluginPath + "/../qml/"
files: [
"QtQml/**",
"QtQuick/**",
"QtQuick.2/**",
"QtPositioning/**",
"QtLocation/**"
]
excludeFiles: ["**/*d.dll"]
qbs.install: true
qbs.installDir: "../../qml"
qbs.installSourceBase: prefix
}

Related

Is there a way to include whole folder with changelogs in Liquibase db versioning?

I have a problem with Liquibase database versioning, because I want to include all changelog files in folder, without specifing its names and do update using them. Is that possible? My structure:
db--
|
--release-v1
|
--fistchangelog.sql
--secondchangelog.sql
|
--release-v2
|
--newchangelog.sql
...
And with every release I want to use all *.sql files from its folder. I don't want to hardcode names of sql files. I use only liquibase command lines for CI/CD in Azure.
I found something like (liquibase.org/get-started/best-practices), but it only works with xml files and I use sql extension.
I have one idea but it seems bad for me and I ll use it as a last resort. Just making a loop, for every file in folder, in cmd...
Does someone know is there a simpler and better way?
You can do like this:
have a parent change log file:
databaseChangeLog = {
include file: "releases/ref1.groovy", relativeToChangelogFile: true
include file: "releases/release1.groovy", relativeToChangelogFile: true
include file: "releases/release2.groovy", relativeToChangelogFile: true
include file: "releases/release3.groovy", relativeToChangelogFile: true
}
in releases folder ref1 file can have:
databaseChangeLog = {
include file: "../tables/changelog.groovy", relativeToChangelogFile: true
}
So inside the same releases folder you can have tables folder which then have create, delete update folders. So you can have another file in tables like, in create folder, you have all the necessary files that have been added in different releases:
databaseChangeLog = {
include file: "create/changelog.groovy", relativeToChangelogFile: true
include file: "update/changelog.groovy", relativeToChangelogFile: true
include file: "data/changelog.groovy", relativeToChangelogFile: true
}
finally in releases main folder you can add a file like release1.groovy:
databaseChangeLog = {
include file: "../tables/create/your_structured_sql_file.groovy",
relativeToChangelogFile: true
}
These are in groovy but the structuring is the same.
i think you should just use "includeAll" tag. Then liquibase will execute all .sql files inside the folder. but remember that if you not specifying every single file, Liquibase will execute those files in alphabetical order.
Sth like:
<includeAll path="com/example/changelogs/"/>
Read here -> https://docs.liquibase.com/concepts/changelogs/attributes/includeall.html

AWS CDK asset path is incorrect

On September 6, I ran a build using CodePipeline. It generates a CloudFormation template for a project's stack using CDK. The stack has assets (a Lambda Layer), and the assets are correctly placed in the cdk.out folder. This can be seen in the CloudFormation template:
"Metadata": {
"aws:cdk:path": "MyStack/MyLayer/Resource",
"aws:asset:path": "asset.ccb8fd8b4259a8f517879d7aaa083679461d02b9d60bfd12725857d23567b70f",
"aws:asset:property": "Content"
}
Starting yesterday, builds were failing with "Uploaded file must be a non-empty zip". When I investigated further, I noticed that the template was no longer correct. It has the asset path set to the source code of the Lambda instead:
"Metadata": {
"aws:cdk:path": "MyStack/MyLayer/Resource",
"aws:asset:path": "/codebuild/output/src216693626/src/src/lambdas/layers",
"aws:asset:property": "Content"
}
When I build, I've added additional commands to the buildspec file which shows that the assets.abcdef folder has the layer and its dependencies, while the src folder does not. Yet the template is now different.
No code was changed in this time period, and I've tried both CDK version 1.105.0 and 1.119.0.
This code declares the Layer:
new lambdapython.PythonLayerVersion(this.stack, 'MyLayer', {
entry: path.join(__dirname, '../../src/lambdas/layers'),
description: 'Common utilities for the Lambdas',
compatibleRuntimes: [lambda.Runtime.PYTHON_3_8],
layerVersionName: `${Aws.STACK_NAME}Utils`,
});
Is there a known way for me to force the stack to use the assets in the cdk.out folder? Has something changed in the last couple of days with respect to how CDK generates the template's asset path?
It turns out that I had added a cdk ls to print out additional debugging information while troubleshooting another problem. That command re-synthesized the stack, but with the incorrect asset path.
build: {
commands: [
'cd ' + config.cdkDir,
'cdk synth',
'cdk ls --long'
]
}
The solution was to delete the cdk ls --long from the buildspec definition.

Linking to multiple subdirectories using :repo_tree

My repository is set up similar to the following:
repo_base
- artwork
- app
- designsystem
- api
Since each of the other folders in the repo (e.g. app, api, designsystem) depend on artwork, I have symlinks in place when running locally. This is working fine, as the path for images in the designsystem subdirectory is something like ../../artwork. When you check out the repository, the entire tree is checked out, so the symlinks are pointing to the correct directory.
However, when I deploy with capistrano, I use :repo_tree to only deploy a portion of the overall monorepo. For example, the deploy.rb script for the designsystem folder looks like:
# config valid for current version and patch releases of Capistrano
lock "~> 3.11.0"
set :application, "designsystem"
set :repo_url, "git#gitlab.com:myuser/mymonorepo"
set :deploy_to, "/var/www/someplace.net/designsystem.someplace.net"
set :deploy_via, "remote_cache_with_project_root"
set :repo_tree, 'designsystem'
set :log_level, :error
before 'deploy:set_current_revision', 'deploy:buildMonolith'
The problem, of course, is that this only ends up deploying the designsystem subdirectory. Thus, the symlinks aren't valid, and are actually skipped in the building (buildMonolith step).
I'm wondering how I might go about having capistrano check out another subdirectory, artwork, and placing it somewhere in the repository source tree.
I was able to solve this by adding a capistrano task called assets.rb:
require 'pathname'
##
# Import assets from a top level monorepo directory into the current working
# directory.
#
# When you use :repo_tree to deploy a specific directory of a monorepo, but your
# asset repository is in a different directory, you need to check out this
# top-level directory and add it to the deployment path. For example, if your
# monorepo directory structure looks something like:
#
# - /app
# - src/
# - assets -> symlink to ../../assets
# - /assets
# - /api
#
# And you want to deploy /app, the symlink to the upper directory won't exist if
# capistrano is configured to use :repo_tree "app". In order to overcome this,
# this task checks out a specified piece of the larger monorepo (in this case,
# the assets directory), and places it in the deployment directory at a
# specified location.
#
# Configuration:
# In your deploy/<stage>.rb file, you will need to specify two variables:
# - :asset_path - The location within the deployment directory where the
# assets should be placed. Relative to the deployment working
# directory.
# - :asset_source - The location of the top-level asset folder in the
# monorepo. Relative to the top level of the monorepo (i.e.
# the directory that would be used as a deployment if
# :repo_tree was not specified).
#
# In the above example, you would specify:
#
# set :asset_path, "src/assets"
# set :asset_source, "assets"
#
namespace :deploy do
desc "Import assets from a top-level monorepo directory"
task :import_assets do
on roles(:all) do |host|
within repo_path do
final_asset_location = "#{release_path}/#{fetch(:asset_path)}"
asset_stat_result = capture "stat", "-t", "#{final_asset_location}"
asset_stat_result = asset_stat_result.split(" ")
if asset_stat_result[0] == "#{final_asset_location}"
info "Removing existing asset directory #{final_asset_location}..."
execute "rm", "-rf", "#{final_asset_location}"
end
source_dir = Pathname.new(final_asset_location).parent.to_s
info "Importing assets to #{source_dir}/#{fetch(:asset_source)}"
execute "GIT_WORK_TREE=#{source_dir}", :git, "checkout", "#{fetch(:branch)}", "--", "#{fetch(:asset_source)}"
info "Moving asset directory #{source_dir}/#{fetch(:asset_source)} to #{final_asset_location}..."
execute :mv, "#{source_dir}/#{fetch(:asset_source)}", "#{final_asset_location}"
end
end
end
end
It would be nice if I could somehow link into the git scm plugin, rather than calling git from the command line directly.

Group Item: cannot install file to same location

In my project, I have several plugins depending on a single module, containing a Group item similar to:
Group {
name: "group"
qbs.install: true
qbs.installDir: "../"
files: <filename>
}
But compilation fails with "error: Cannot install files 'filename' and 'filename' to the same location 'location'". Basically, qbs cannot copy same file to same location twice (seems illogical to me)
How can this bug be resolved or is there any elegant workaround?
This is a job for the qbs.installSourceBase property. Basically, you set this to the base directory containing the files in your Group, and Qbs will install the listed files into qbs.installDir hierarchically based on their paths relative to the aforementioned base directory.
For example, given the following Group:
// defined in /source/myproject/myproject.qbs
Group {
qbs.install: true
qbs.installDir: "share/stuff"
qbs.installSourceBase: "." // relative to /source/myproject
files: [
"fileA.txt",
"fileB.txt",
"subdir/fileB.txt",
]
}
and the following command line invocation:
$ qbs [...] --install-root /sample/some-root
the following filesystem hierarchy will result:
/sample/some-root/share/stuff/fileA.txt
/sample/some-root/share/stuff/fileB.txt
/sample/some-root/share/stuff/subdir/fileB.txt
See the Qbs Installation Properties documentation for more info.
There is a workaround, which may require some restructuring of a project:
instead of:
Module {
name: "somemodule"
// module properties set to dependant products
Group {
// files to install
qbs.install: true
}
}
we can use:
Product {
name: "somemodule"
Group {
// files to install
qbs.install: true
}
Export {
// module properties set to dependant products
}
}
This way, files are only installed once when steps for mymodule are run, thus eliminating the conflict. Module properties, exported via Export Item, work just as ones exported via Module.
Limitations:
Product has to be added to references of the Project Item
Modules cannot depend on Product Items, which may require to restructure all dependant modules into Project/Export pairs too

JSDoc: Lookup tutorials from different directories

Is there a way to ask JSDoc (either in the command line or through grunt-jsdoc plugin) to lookup tutorials from different directories ?
As per the documentation, -u allows to specify the Directory in which JSDoc should search for tutorials. (it says the Directory instead of Directories).
I tried the following with no luck:
specify different strings separated by space or comma
specify one string with shell/ant regular expression
As suggested by #Vasil Vanchuk, a solution would be creating links to all tutorial files within a single directory. As such, JSDoc3 will be happy and it will proceed with the generation of all tutorials.
Creating/maintaining links manually would be a tedious task. Hence, and for people using grunt, the grunt-contrib-symlink come in handy. Using this plugin, the solution is reduced to a config task.
My Gruntfile.js looks like the following:
clean:['tmp', 'doc'],
symlink: {
options: {
overwrite: false,
},
tutorials: {
files: [{
cwd: '../module1/src/main/js/tut',
dest: 'tmp/tutorial-generation-workspace',
expand: true,
src: ['*'],
}, {
cwd: '../module2/src/main/js/tut',
dest: 'tmp/tutorial-generation-workspace',
expand: true,
src: ['*'],
}]
}
},
jsdoc: {
all: {
src: [
'../module1/src/main/js/**/*.js',
'../module2/src/main/js/**/*.js',
'./README.md',
],
options: {
destination: 'doc',
tutorials: 'tmp/tutorial-generation-workspace',
configure : "jsdocconf.json",
template: 'node_modules/grunt-jsdoc/node_modules/ink-docstrap/template',
},
}
},
grunt.loadNpmTasks('grunt-contrib-symlink');
grunt.loadNpmTasks('grunt-jsdoc');
grunt.registerTask('build', ['clean', 'symlink', 'jsdoc']);
grunt.registerTask('default', ['build']);
Integrating new module is translated by updating symlink and jsdoc tasks.
You could just copy the files instead of linking to a bunch of directories.
E.g. create a dir in your project for documentation in which you'll copy over all relevant tutorials from where ever.
Then, in your npm scripts you can have something like this:
"copy:curry": "cp node_modules/#justinc/jsdocs/tutorials/curry.md doc/tutorials",
"predocs": "npm run copy:curry",
The docs script (not shown) runs jsdoc. predocs runs automatically before docs and, in this case copies over a tutorial in one of my packages over to doc/tutorials. You can then pass doc/tutorials as the single directory housing all your tutorials.
In predocs you can keep adding things to copy with bash's && - or if that's not available for whatever reason, you'll find npm packages which let you do this (therefore not relying on whatever shell you're using).
Now that I think about it, it's best to also delete doc/tutorials in predocs:
"predocs": "rm -rf doc/tutorials && mkdir -p doc/tutorials && npm run copy:tutorials",
That way any tutorials you once copied there (but are now not interested in) will be cleared each time you generate the docs.
btw, I opened an issue for this: https://github.com/jsdoc3/jsdoc/issues/1330