How to change unmanagedBase according to crossScalaVersions in sbt - sbt

I have to use different unmanaged jar files depending on the version of Scala being used. It is possible to do this one Scala version at a time with a built.sbt like
val defaultScalaVersion = "2.12.4"
scalaVersion := defaultScalaVersion // because I can't figure out how to read value
val majorMinor = {
val versionRegex = "(\\d+)\\.(\\d+)\\.(\\d+)".r
val versionRegex(major, minor, update) = defaultScalaVersion
major + "." + minor
}
unmanagedBase := baseDirectory.value / ("lib-" + majorMinor)
However, if I need to publish for two different versions using something like
crossScalaVersions := Seq("2.11.11", "2.12.4")
of course my majorMinor and unmanagedBase do not get changed. How can this be arranged?

You can read the current major/minor version of Scala with scalaBinaryVersion.value and use it directly:
unmanagedBase := baseDirectory.value / s"lib-${scalaBinaryVersion.value}"
You can also use CrossVersion.partialVersion to extract major/minor components of the version. So in case you want a different formatting of the version you could adapt your current solution:
lazy val majorMinor = Def.setting {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((major, minor)) => s"${major}-${minor}"
}
}
unmanagedBase := baseDirectory.value / s"lib-${majorMinor.value}"
Notice that to be able to use .value in the majorMinor value definition, you need to use the Def.setting macro (or Def.task if you're referring to a task).

Related

Golang Map YAML Objects

I have a yaml configuration file that contains sets of configuration commands to send to network devices. Inside of each set, there are vendor-specific keys and the values for each vendor key can be either a configuration command string, a list of configuration command strings, or a list of key-value pairs mapping a vendor-specific model string to a configuration command string. Below is an example:
# example.yml
---
cmds:
setup:
cisco: "terminal length 0"
config:
cisco:
- basic : "show version"
- basic : "show boot"
"3560" : "3560 boot command"
"2960x": "2960x boot command"
- basic : "dir flash:"
"3560" : "3560 dir command"
cleanup:
cisco: ["terminal no length", "quit"]
I want to combine these commands into a map like so:
var cmdMap = map[string][]string{
"cisco": []string{
"terminal length 0",
"show version",
"show boot",
"dir flash:",
"terminal no length",
"quit",
},
"cisco.3560": []string{
"terminal length 0",
"show version",
"3560 boot command",
"3560 dir command",
"terminal no length",
"quit",
},
"cisco.2960x": []string{
"terminal length 0",
"show version",
"2960x boot command",
"dir flash:",
"terminal no length",
"quit",
}
}
I am using spf13/viper to handle parsing the yaml file and have been able to add the specific commands to each vendor and model, but adding the commands that apply to both vendor and specific model is where I am stuck. This is the actual output of my program followed by my code:
$ go run main.go example.yml
cmdMap["cisco"]
terminal length 0
show version
show boot
dir flash:
terminal no length
quit
# missing terminal length 0, show version, etc.
cmdMap["cisco.3560"]
3560 boot command
3560 dir command
# missing terminal length 0, show version, etc.
cmdMap["cisco.2960x"]
2960x boot command
My code:
package main
import (
"github.com/spf13/viper"
"fmt"
"flag"
"log"
)
func main() {
flag.Parse()
cfgFile := flag.Arg(0)
v := viper.New()
v.SetConfigType("yaml")
v.SetConfigFile(cfgFile)
if err := v.ReadInConfig(); err != nil {
log.Fatal(err)
}
for k, v := range MapCfgCmds(v.GetStringMap("cmds")) {
fmt.Printf("cmdMap[\"%s\"]\n", k)
for _, cmd := range v {
fmt.Println(cmd)
}
fmt.Println()
}
}
func MapCfgCmds(cfgCmds map[string]interface{}) map[string][]string {
cmdMap := make(map[string][]string)
for _, cmdSet := range cfgCmds {
cmdSet, _ := cmdSet.(map[string]interface{})
for vendor, cmdList := range cmdSet {
switch cmds := cmdList.(type) {
case string:
// single string command (i.e., vendor: cmd)
cmdMap[vendor] = append(cmdMap[vendor], cmds)
case []interface{}:
for _, cmd := range cmds {
switch c := cmd.(type) {
case string:
// list of strings (i.e., vendor: [cmd1,cmd2,...,cmdN])
cmdMap[vendor] = append(cmdMap[vendor], c)
case map[interface{}]interface{}:
// This is where I am stuck
//
// list of key-value pairs (i.e., vendor: {model: modelCmd})
for model, modelCmd := range c {
modelCmd, _ := modelCmd.(string)
if model == "basic" {
cmdMap[vendor] = append(cmdMap[vendor], modelCmd)
continue
}
modelKey := fmt.Sprintf("%s.%s", vendor, model)
cmdMap[modelKey] = append(cmdMap[modelKey], modelCmd)
}
}
}
}
}
}
return cmdMap
}
How can I combine the "universal" and model-specific commands to get the expected cmdMap value from above?
I think viper is not helping you here, in the sense that viper does a lot of things you don't need, but it doesn't do one thing you could use here - clear mapping of the data. If you use the yaml library directly, you could declare a structure that corresponds to your data and makes it easier to understand it.
There are several possible approaches to your problem, here is my attempt at solving it (you might need to tweak few things as I wrote it in the editor, without compiling it):
type Data struct {
Cmds struct {
Setup map[string]interface{} `yaml:"setup"`
Config map[string][]map[string]string `yaml:"config"`
Cleanup map[string][]string `yaml:"cleanup"`
} `yaml:"cmds"`
}
data := Data{}
err := yaml.Unmarshal([]byte(input), &data)
if err != nil {
log.Fatalf("error: %v", err)
}
setupCmds := make(map[string][]string)
cleanupCmds := make(map[string][]string)
result := make(map[string][]string)
// Prepare setup commands, grouped by vendor
for vendor, setupCmd := range data.Cmds.Setup {
setupCmds[vendor] = append(setupCmds[vendor], setupCmd)
}
// Prepare cleanup commands, grouped by vendor
for vendor, commands := range data.Cmds.Cleanup {
cleanupCmds[vendor] = append(cleanupCmds[vendor], commands...)
}
// iterate over vendors and models, combine with setup & cleanup commands and store in result
for vendor, configCmds := range data.Cmds.Config { // vendor = string (e.g. "cisco"), configCmds = []map[string][string] (e.g. - basic: "show version")
// we now how many config commands there will be
result[vendor] = make([]string, len(configCmds))
// variantsCache will store all variants we've seen so far
variantsCache := make(map[string]struct{})
for i, model := range models { // i = int (number of command) model = map[string]string
// we assume "basic" is available for each command
result[vendor][i] = model["basic"]
for variant, command := range model { // variant = string (e.g. "basic"), command = string (e.g. "show version")
if variant == "basic" {
// we already covered that
continue
}
variantKey := vendor + "." + variant
variantsCache[variantKey]
if _, ok := result[variantKey]; !ok {
// first command for this model, create a slice
result[variantKey] = make([]string, len(configCmds))
}
result[variantKey][i] = command
}
}
// We need to iterate over all commands for all variants and copy "basic" command if there is none
for variant, _ := range variantsCache {
for i, command := range result[variant] {
if command == "" {
// copy the "basic" command, since there was no variant specific command
result[variant][i] = result[vendor][i]
}
}
}
}
// combine setup and cleanup with config
for variant, _ := result {
// will return "cisco" for both "cisco" and "cisco.x3650"
vendor := strings.Split(variant, ".")[0]
result[variant] = append(setupCmds[vendor], result[variant]...)
result[variant] = append(result[variant], cleanupCmds[vendor]...)
}
return result
You can combine them after the loop of constructing cmdMap.
for vendor := range cmdMap {
// get the base name of the vendor
s := strings.SplitN(vender, ".", 2)
// if vendor is a basic one, skip it.
if len(s) == 1 {
continue
}
// add basic cmd into the specified ones.
base = s[0]
cmdMap[vendor] = append(cmdMap[vendor], cmdMap[base]...)
}
Note that cmdMap[base]... is a use of variadic parmaters of append. You can see more here: https://golang.org/ref/spec#Passing_arguments_to_..._parameters

Getting errors when Browsery bundle with SquishIt

I am currently refactoring the javascript portions of a web site, and now I have bundled some scripts together using Browserify. The resulting script is bundled along with other resources using SquishIt. In Debug mode, when SquishIt is not bundling all the scripts together everything seems to work just fine, but when running in Production, and SquishIt bundles everything together I get errors from the Browserify part of my bundle. The error is complaining that r has no length property (see line 18) below. This part of the code is created by Browserify when bundling the scripts.
(function e(t, n, r) {
function s(o, u) {
if (!n[o]) {
if (!t[o]) {
var a = typeof require == "function" && require;
if (!u && a) return a(o, !0);
if (i) return i(o, !0);
var f = new Error("Cannot find module '" + o + "'");
throw f.code = "MODULE_NOT_FOUND", f
}
var l = n[o] = {
exports: {}
};
t[o][0].call(l.exports, function(e) {
var n = t[o][1][e];
return s(n ? n : e)
}, l, l.exports, e, t, n, r)
}
return n[o].exports
}
var i = typeof require == "function" && require;
for (var o = 0; o < r.length; o++) s(r[o]);
return s
})({
I really can't think of anything that using SquishIt to bundle all the scripts would break the logic of the browserified scripts. What could be the cause of this? This gist shows the entire source code, in case that is relevant.
I have not changed anything on the ASP.NET side (in the bundling), and the relevant part of my ´Head.ascx´ looks like this:
Bundle.JavaScript()
.Add(Assets.JavaScript.GetUrl("main.js").ToString())
.Add(Assets.JavaScript.GetUrl("Plugins/raphael-min.js").ToString())
.Add(Assets.JavaScript.GetUrl("Plugins/vector_map.js").ToString())
// more ...
.Render("~/Content/"+Assets.VersionString+"/Scripts/Combined/combined.js")
Have a look at this comment it may help https://github.com/jetheredge/SquishIt/issues/320#issuecomment-139921409
Is there a reason you need to use two different bundling solutions?

Grunt task for making sure you have copyrights on each file

I need to make sure there's copyrights notice at the beginning of each file.
How can I use grunt to fail my build in case the copyrights statement is missing?
First of all, I'm assuming you are referring to *.js or *.html or other similar work files, and not to graphic or binary files.
This can be done, with a grunt.registerTask which will:
1. loop through all relevant files
2. Read and compare first line to copyright line
3. If different - re-write file but a new first line which will be the copyright info
Pretty simple. Again - this will not work on binary files. I wrote this for you but it seems very useful, I might consider adding it as a plugin. Field tested:
run it by grunt verifyCopyright and also make sure that if your files are in a different directory your change it, and also if you want to process other files add them to the list as well. good luck...
grunt.registerTask('verifyCopyright', function () {
var fileRead, firstLine, counter = 0, fileExtension, commentWrapper;
copyrightInfo = 'Copyright by Gilad Peleg #2013';
//get file extension regex
var re = /(?:\.([^.]+))?$/;
grunt.log.writeln();
// read all subdirectories from your modules folder
grunt.file.expand(
{filter: 'isFile', cwd: 'public/'},
["**/*.js", ['**/*.html']])
.forEach(function (dir) {
fileRead = grunt.file.read('public/' + dir).split('\n');
firstLine = fileRead[0];
if (firstLine.indexOf(copyrightInfo > -1)) {
counter++;
grunt.log.write(dir);
grunt.log.writeln(" -->doesn't have copyright. Writing it.");
//need to be careful about:
//what kind of comment we can add to each type of file. i.e /* <text> */ to js
fileExtension = re.exec(dir)[1];
switch (fileExtension) {
case 'js':
commentWrapper = '/* ' + copyrightInfo + ' */';
break;
case 'html':
commentWrapper = '<!-- ' + copyrightInfo + ' //-->';
break;
default:
commentWrapper = null;
grunt.log.writeln('file extension not recognized');
break;
}
if (commentWrapper) {
fileRead.unshift(commentWrapper);
fileRead = fileRead.join('\n');
grunt.file.write( 'public/' + dir, fileRead);
}
}
});
grunt.log.ok('Found', counter, 'files without copyright');
})
Instead of checking to see if it's there and failing, why not just have a task that automatically injects it? See grunt-banner.
https://github.com/thekua/grunt-regex-check could be what you want. You define the regex to check for and if it finds it then the task fails.

Using Closure compiler with Underscore.js _.template

Is there any way to compile Underscore.js templates on the server and get the Closure compiler to work with the generated code?
The main problem is that _.template:
_.template = function(str, data) {
var c = _.templateSettings;
var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
'with(obj||{}){__p.push(\'' +
str.replace(/\\/g, '\\\\')
.replace(/'/g, "\\'")
.replace(c.interpolate, function(match, code) {
return "'," + code.replace(/\\'/g, "'") + ",'";
})
.replace(c.evaluate || null, function(match, code) {
return "');" + code.replace(/\\'/g, "'")
.replace(/[\r\n\t]/g, ' ') + "__p.push('";
})
.replace(/\r/g, '\\r')
.replace(/\n/g, '\\n')
.replace(/\t/g, '\\t')
+ "');}return __p.join('');";
var func = new Function('obj', tmpl);
return data ? func(data) : func;
};
generates JavaScript with a with-statement in it. The two obvious routes are:
modify Underscore.js's _.template not to generate withs
coerce Closure into playing nice
Is the second option possible?
Generally, the JS engines perform better without "with", so if generating it without "with" is an option that is likely the best solution.
Otherwise your options depend on whether you are hoping to using Closure Compilers ADVANCED mode. In SIMPLE mode, the compiler won't rename your properties on the template, and will assume that any undeclared variable are globals. So as long are your template object isn't causing any local variables to be shadowed it might "just work".

Dynamic properties in Scala

Does Scala support something like dynamic properties? Example:
val dog = new Dynamic // Dynamic does not define 'name' nor 'speak'.
dog.name = "Rex" // New property.
dog.speak = { "woof" } // New method.
val cat = new Dynamic
cat.name = "Fluffy"
cat.speak = { "meow" }
val rock = new Dynamic
rock.name = "Topaz"
// rock doesn't speak.
def test(val animal: Any) = {
animal.name + " is telling " + animal.speak()
}
test(dog) // "Rex is telling woof"
test(cat) // "Fluffy is telling meow"
test(rock) // "Topaz is telling null"
What is the closest thing from it we can get in Scala? If there's something like "addProperty" which allows using the added property like an ordinary field, it would be sufficient.
I'm not interested in structural type declarations ("type safe duck typing"). What I really need is to add new properties and methods at runtime, so that the object can be used by a method/code that expects the added elements to exist.
Scala 2.9 will have a specially handled Dynamic trait that may be what you are looking for.
This blog has a big about it: http://squirrelsewer.blogspot.com/2011/02/scalas-upcoming-dynamic-capabilities.html
I would guess that in the invokeDynamic method you will need to check for "name_=", "speak_=", "name" and "speak", and you could store values in a private map.
I can not think of a reason to really need to add/create methods/properties dynamically at run-time unless dynamic identifiers are also allowed -and/or- a magical binding to an external dynamic source (JRuby or JSON are two good examples).
Otherwise the example posted can be implemented entirely using the existing static typing in Scala via "anonymous" types and structural typing. Anyway, not saying that "dynamic" wouldn't be convenient (and as 0__ pointed out, is coming -- feel free to "go edge" ;-).
Consider:
val dog = new {
val name = "Rex"
def speak = { "woof" }
}
val cat = new {
val name = "Fluffy"
def speak = { "meow" }
}
// Rock not shown here -- because it doesn't speak it won't compile
// with the following unless it stubs in. In both cases it's an error:
// the issue is when/where the error occurs.
def test(animal: { val name: String; def speak: String }) = {
animal.name + " is telling " + animal.speak
}
// However, we can take in the more general type { val name: String } and try to
// invoke the possibly non-existent property, albeit in a hackish sort of way.
// Unfortunately pattern matching does not work with structural types AFAIK :(
val rock = new {
val name = "Topaz"
}
def test2(animal: { val name: String }) = {
animal.name + " is telling " + (try {
animal.asInstanceOf[{ def speak: String }).speak
} catch { case _ => "{very silently}" })
}
test(dog)
test(cat)
// test(rock) -- no! will not compile (a good thing)
test2(dog)
test2(cat)
test2(rock)
However, this method can quickly get cumbersome (to "add" a new attribute one would need to create a new type and copy over the current data into it) and is partially exploiting the simplicity of the example code. That is, it's not practically possible to create true "open" objects this way; in the case for "open" data a Map of sorts is likely a better/feasible approach in the current Scala (2.8) implementation.
Happy coding.
First off, as #pst pointed out, your example can be entirely implemented using static typing, it doesn't require dynamic typing.
Secondly, if you want to program in a dynamically typed language, program in a dynamically typed language.
That being said, you can actually do something like that in Scala. Here is a simplistic example:
class Dict[V](args: (String, V)*) extends Dynamic {
import scala.collection.mutable.Map
private val backingStore = Map[String, V](args:_*)
def typed[T] = throw new UnsupportedOperationException()
def applyDynamic(name: String)(args: Any*) = {
val k = if (name.endsWith("_=")) name.dropRight(2) else name
if (name.endsWith("_=")) backingStore(k) = args.first.asInstanceOf[V]
backingStore.get(k)
}
override def toString() = "Dict(" + backingStore.mkString(", ") + ")"
}
object Dict {
def apply[V](args: (String, V)*) = new Dict(args:_*)
}
val t1 = Dict[Any]()
t1.bar_=("quux")
val t2 = new Dict("foo" -> "bar", "baz" -> "quux")
val t3 = Dict("foo" -> "bar", "baz" -> "quux")
t1.bar // => Some(quux)
t2.baz // => Some(quux)
t3.baz // => Some(quux)
As you can see, you were pretty close, actually. Your main mistake was that Dynamic is a trait, not a class, so you can't instantiate it, you have to mix it in. And you obviously have to actually define what you want it to do, i.e. implement typed and applyDynamic.
If you want your example to work, there are a couple of complications. In particular, you need something like a type-safe heterogenous map as a backing store. Also, there are some syntactic considerations. For example, foo.bar = baz is only translated into foo.bar_=(baz) if foo.bar_= exists, which it doesn't, because foo is a Dynamic object.

Resources