I have a target that looks like this:
Target "builddotnetcode" (fun _ ->
!! "../Mercury.sln"
|> MSBuildRelease null "Clean,Build"
|> Log "MercuryBuild - Output: "
)
I want to simply set the verbosity in there somewhere. As far as I can tell from the docs you need to specify the Verbosity member of the MSBuildParams object. But build is the only MSBuildHelper function that provides a way to pass a MSBuildParams. Using build I then need to specify Configuration=Release property, the project list, and remove the pipeline to the Log. It seems like there ought to be a simpler way that does not cause me to redefine the entire task. Am I missing something?
So what i did is the following. The reason i did is it this was as I want to create a log file per solution file that I am building
let loggerConfig : list<MSBuildFileLoggerConfig> = [
{
Number = 1
Filename = Some (baseDir + name + "_build.log")
Verbosity = Some MSBuildVerbosity.Minimal
Parameters = Some [MSBuildLogParameter.Append]
}
]
let setParams defaults =
{ defaults with
Verbosity = Some MSBuildVerbosity.Minimal
Targets = ["Build"]
MaxCpuCount = Some (Some 4)
FileLoggers = Some loggerConfig
ToolsVersion = Some "12.0"
Properties =
[
"Optimize", "True"
"DebugSymbols", "True"
"Configuration", buildMode
]
}
Lastly the only msbuild task that I could see that will let you override the msbuilddefaults was standard build.
build setParams solution
|> DoNothing
Related
I am attempting to reference assigned property generatorName when setting outputDir.
Attempted to reference generatorName property using same syntax as other task properties (i.e. $buildDir). Also attempted to more fully qualify the property name openApiGenerator.generatorName.
openApiGenerate {
verbose = false
generatorName = "html2" // assignment to property
inputSpec = "$buildDir/swagger/testing.yml".toString()
//outputDir = "$buildDir/generated".toString()
outputDir = "$buildDir/generated/$generatorName".toString() // fails
apiPackage = "org.openapi.example.api"
invokerPackage = "org.openapi.example.invoker"
modelPackage = "org.openapi.example.model"
// debugging code
println " buildDir: $buildDir".toString()
println " generatorName: $generatorName".toString() // this fails
}
output from debugging code shows failure to reference generatorName property:
> Configure project :
buildDir: C:\Users\jgunchy\repos\testingproject\build
generatorName: property(class java.lang.String, fixed(class java.lang.String, html2))
This is an observable property, not a string. You should be able to access the underlying string using .get() like this:
openApiGenerate {
verbose = false
generatorName = "html2"
inputSpec = "$buildDir/swagger/testing.yml".toString()
outputDir = "$buildDir/generated/${generatorName.get()}".toString()
apiPackage = "org.openapi.example.api"
invokerPackage = "org.openapi.example.invoker"
modelPackage = "org.openapi.example.model"
}
Another option would be to use configuration rather than the project extension container's properties directly. For instance, add to gradle.properties:
generatorName=html2
Then, your configuration would look like this:
openApiGenerate {
verbose = false
generatorName = project.ext.generatorName
inputSpec = "$buildDir/swagger/testing.yml".toString()
outputDir = "$buildDir/${project.ext.generatorName}".toString()
apiPackage = "org.openapi.example.api"
invokerPackage = "org.openapi.example.invoker"
modelPackage = "org.openapi.example.model"
}
$buildDir is a getter on the Project instance with a toString() method that happens to output the File path, which is why it behaves differently.
I'd like to change the name of my output .apk files. However, I want to have "-debug" or "-release" appended depending on the build type.
Here are the output names I want:
MyApp-0.0.1-debug.apk
MyApp-0.0.1-release.apk
I'm unfamiliar with Gradle and haven't found how to do this, I know I just need to access the buildType within the following code but can't find how to do this.
Currently my output is "MyApp-0.0.1.apk" regardless of buildType. How can I change the code below to alter this?
android.libraryVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.aar')) {
def fileName
def bType = ""
// bType = "-" + something.buildType
fileName = "${archivesBaseName}-${project.version}${bType}.aar"
output.outputFile = new File(outputFile.parent, fileName)
}
}
}
The build type is part of the variant; you're iterating over all the variants in your loop. You can get the build type name via:
variant.buildType.name
You can find (partially complete) API docs at http://tools.android.com/tech-docs/new-build-system/user-guide
For anyone arriving here late, this version works for me in April 2020.
Just place this code inside your buildTypes element ( android or defaultConfig work just as well).
applicationVariants.all { variant ->
def customBuildName = ""
if(variant.buildType.name == "release") customBuildName = "release-name.apk"
else customBuildName = "build-name.apk"
variant.outputs.all {
outputFileName = customBuildName
println("name of ${variant.buildType.name} build is ${outputFileName}")
}
}
I am trying to build a solution where one of the projects needs to be build with the unsafe flag on, it is set correctly in the project however when building I get the error:
"Unsafe code may only appear if compiling with /unsafe"
This is my target at the moment
Target "CompileApp" (fun _ ->
!! #"**\*.csproj"
|> MSBuildRelease buildDir "Build"
|> Log "AppBuild-Output: "
)
I tried adding MsBuildParams but not sure how to use them yet (ie there doesnt seem to be an option in MsBuildRelease to add something like this
let setParams defaults =
{ defaults with
Verbosity = Some(Quiet)
Targets = ["Build"]
Properties =
[
"AllowUnsafeBlocks", "True"
"Configuration", "Release"
]
}
Also would the best option here be create two different targets for projects with safe and unsafe code, of would there be a better way?
I found that the AllowUnsafeBlocks=true element was only defined under the DEBUG|AnyCPU and Release|AnyCPU PropertyGroups in my project file.
Using this fixed it for me:
Target "BuildApp" (fun _ ->
!! ".\**\MyApp.*.csproj"
|> MSBuild buildDir "Build" ["Configuration", "Release"; "Platform", "AnyCPU"]
|> Log "AppBuild-Output: "
)
Hope this helps.
Ok I think this might be the way:
Target "CompileUnsafe" (fun _ ->
let buildMode = getBuildParamOrDefault "buildMode" "Release"
let setParams defaults =
{ defaults with
Verbosity = Some(Quiet)
Targets = ["Build"]
Properties =
[
"Optimize", "True"
"DebugSymbols", "True"
"Configuration", buildMode
"AllowUnsafeBlocks", "True"
]
}
build setParams "./ProjectPlugins.sln"
)
IF there are better solutions I'm all ears (the solution was there in the docs and I just missed it)
I have the following code in my build.gradle
Contents in version.properties are:
buildVersion=1.2.3
Value of $v variable during the Gradle build is coming as: 1.2.3
Value of $artifactoryVersion variable in JENKINS build is coming as: 1.2.3.1, 1.2.3.2, 1.2.3.x ... and so on where the 4th digit is Jenkins BUILD_NUMBER available to gradle build script during Jenkins build.
BUT, when I'm running this build.gradle on my desktop where I dont have BUILD_NUMBER variable available or set in my ENVIRONMENT variables, I get an error saying trim() can't work on null. (as there's no BUILD_NUMBER for Desktop/local build).
I'm trying to find a way i.e.
What should I code in my script so that if BUILD_NUMBER is not available, then instead of gradle build processing failing for an error, it'd set jenkinsBuild = "0" (hard coded) otherwise, pick what it gets during Jenkins build.
For ex: in Bash, we set a variable var1=${BUILD_NUMBER:-"0"} which will set var1 to a valid Jenkins BUILD number if it's available and set to a value, otherwise if it's NULL, then var1 = "0".
I DON'T want to have each developer/user set this BUILD_NUMBER in some property file. All I want is, if this variable doesn't exist, then the code should put "0" in jenkinsBuilds variable and doesn't error out during desktop builds. I know during Jenkins build, it's working fine.
// Build Script
def fname = new File( 'version.properties' )
Properties props = new Properties()
props.load( new FileInputStream( fname ) )
def v = props.get( 'buildVersion' )
def env = System.getenv()
def jenkinsBuild = env['BUILD_NUMBER'].trim()
if( jenkinsBuild.length() > 0 ) {
artifactoryVersion = "$v.$jenkinsBuild"
}
All you need is some regular Java/Groovy code:
def jenkinsBuild = System.getenv("BUILD_NUMBER") ?: "0"
The code above uses Groovy's "elvis" operator, and is a shorthand for the following code, which uses Java's ternary operator:
def buildNumber = System.getenv("BUILD_NUMBER")
def jenkinsBuild = buildNumber != null ? buildNumber : "0"
Here's the answer to using a Java plain object (JDK8):
public class Sample {
private String region;
private String fruit;
public Sample() {
region = System.getenv().getOrDefault("REGION", null);
fruit = System.getenv().getOrDefault("FRUIT", "apple");
}
}
With the Env-Inject plugin you can get and set build parameters.
For example, under "Inject environment variables to the build process", add a Groovy script such as:
def paramsMap = [:]
def build = Thread.currentThread().executable
def my_var = build.getEnvVars()["MY_PARAM"]
if (!my_var) paramsMap.put("MY_PARAM", "default value")
// Return parameters map
out.println("Injecting parameters:\n" + paramsMap)
return paramsMap
I'm author of the logging package on CRAN, I don't see myself as an R programmer, so I tried to make it as code-compatible with the Python standard logging package as I could, but now I have a question. and I hope it will give me the chance to learn some more R!
it's about hierarchical loggers. in Python I would create a logger and send it logging records:
l = logging.getLogger("some.lower.name")
l.debug("test")
l.info("some")
l.warn("say no")
In my R package instead you do not create a logger to which you send messages, you invoke a function where one of the arguments is the name of the logger. something like
logdebug("test", logger="some.lower.name")
loginfo("some", logger="some.lower.name")
logwarn("say no", logger="some.lower.name")
the problem is that you have to repeat the name of the logger each time you want to send it a logging message. I was thinking, I might create a partially applied function object and invoke that instead, something like
logdebug <- curry(logging::logdebug, logger="some.lower.logger")
but then I need doing so for all debugging functions...
how would you R users approach this?
Sounds like a job for a reference class ?setRefClass, ?ReferenceClasses
Logger <- setRefClass("Logger",
fields=list(name = "character"),
methods=list(
log = function(level, ...)
{ levellog(level, ..., logger=name) },
debug = function(...) { log("DEBUG", ...) },
info = function(...) { log("INFO", ...) },
warn = function(...) { log("WARN", ...) },
error = function(...) { log("ERROR", ...) }
))
and then
> basicConfig()
> l <- Logger$new(name="hierarchic.logger.name")
> l$debug("oops")
> l$info("oops")
2011-02-11 11:54:05 NumericLevel(INFO):hierarchic.logger.name:oops
> l$warn("oops")
2011-02-11 11:54:11 NumericLevel(WARN):hierarchic.logger.name:oops
>
This could be done with the proto package. This supports older versions of R (its been around for years) so you would not have a problem of old vs. new versions of R.
library(proto)
library(logging)
Logger. <- proto(
new = function(this, name)
this$proto(name = name),
log = function(this, ...)
levellog(..., logger = this$name),
setLevel = function(this, newLevel)
logging::setLevel(newLevel, container = this$name),
addHandler = function(this, ...)
logging::addHandler(this, ..., logger = this$name),
warn = function(this, ...)
this$log(loglevels["WARN"], ...),
error = function(this, ...)
this$log(loglevels["ERROR"], ...)
)
basicConfig()
l <- Logger.$new(name = "hierarchic.logger.name")
l$warn("this may be bad")
l$error("this definitely is bad")
This gives the output:
> basicConfig()
> l <- Logger.$new(name = "hierarchic.logger.name")
> l$warn("this may be bad")
2011-02-28 10:17:54 WARNING:hierarchic.logger.name:this may be bad
> l$error("this definitely is bad")
2011-02-28 10:17:54 ERROR:hierarchic.logger.name:this definitely is bad
In the above we have merely layered proto on top of logging but it would be possible to turn each logging object into a proto object, i.e. it would be both, since both logging objects and proto objects are R environments. That would get rid of the extra layer.
See the http://r-proto.googlecode.com for more info.
Why would you repeat the name? It would be more convenient to pass the log-object directly to the function, ie
logdebug("test",logger=l)
# or
logdebug("test",l)
A bit the way one would use connections in a number of functions. That seems more the R way of doing it I guess.