Concourse CI shell commands being quoted - concourse

We are trying to copy multiple jar files in a Concourse CI package.yml file as part of a run step:
run:
path:
args:
- -exc
- |
...
cp project/target/*.jar build-output/.
But Concourse is adding single quotes to the source file, so that it's looking for a file named 'project/target/*.jar', and of course it's not finding it.
+ cp 'project/target/*.jar' build-output/.
cp: can't stat 'project/target/*.jar'; no such file or directory
I even tried putting double quotes around the jar file name, hoping that it might keep Concourse from changing it, but it made no difference.
We want to use file globbing so that we can use this generically, so that we don't need to know the file names ahead of time. Is there any way we can get this to work?

Bizarre. Try specifying the shell:
run:
path: sh <== missing `sh` or the shell you have available in the image
args:
- -exc
- |
...
cp project/target/*.jar build-output/ <== no `.`
Mhhh, actually maybe the quotes are misleading, there is nothing below project/target :-) Try with
run:
path: sh <== missing `sh` or the shell you have available in the image
args:
- -exc
- |
...
# is anything here ?
ls -1 project/target
cp project/target/*.jar build-output/ <== no `.`

set -x mode quotes all arguments; it doesn't mean that it actually quoted the argument. I think you had a red herring, but I'm glad you got it working.

Related

Issues running commands via cloud-init

An open source project I'm working on has components that require Linux and consequently virtualization has generally been the best solution for development and testing new features. I'm attempting to provide a simple cloud-init file for Multipass that will configure the VM with our code by pulling our files from Git and setting them up in the VM automatically. However, even though extra time elapsed for launch seems to indicate the process is being run, no files seem to actually be saved to the home directory, even for simpler cases, i.e.
runcmd:
- [ cd, ~ ]
- [ touch test ]
- [ echo 'test' > test ]
Am I just misconfiguring cloud-init or am I missing something crucial?
There are a couple of problems going on here.
First, your cloud config user data must begin with the line:
#cloud-config
Without that line, cloud-init doesn't know what to do with it. If you were to submit a user-data configuration like this:
#cloud-config
runcmd:
- [ cd, ~ ]
- [ touch test ]
- [ echo 'test' > test ]
You would find the following errors in /var/log/cloud-init-output.log:
runcmd.0: ['cd', None] is not valid under any of the given schemas
/var/lib/cloud/instance/scripts/runcmd: 2: cd: can't cd to None
/var/lib/cloud/instance/scripts/runcmd: 3: touch test: not found
/var/lib/cloud/instance/scripts/runcmd: 4: echo 'test' > test: not found
You'll find the solution to these problems in the documentation, which includes this note about runcmd:
# run commands
# default: none
# runcmd contains a list of either lists or a string
# each item will be executed in order at rc.local like level with
# output to the console
# - runcmd only runs during the first boot
# - if the item is a list, the items will be properly executed as if
# passed to execve(3) (with the first arg as the command).
# - if the item is a string, it will be simply written to the file and
# will be interpreted by 'sh'
You passed a list of lists, so the behavior is governed by "*if the item is a list, the items will be properly executed as if passed to execve(3) (with the first arg as the command)". In this case, the ~ in [cd, ~] doesn't make any sense -- the command isn't being executed by the shell, so there's nothing to expand ~.
The second two commands include on a single list item, and there is no command on your system named either touch test or echo 'test' > test.
The simplest solution here is to simply pass in a list of strings intead:
#cloud-config
runcmd:
- cd /root
- touch test
- echo 'test' > test
I've replaced cd ~ here with cd /root, because it seems better to be explicit (and you know these commands are running as root anyway).

Autocomplete directories in a subfolder with the Fish shell

I'm having trouble getting the 'complete' function in the fish shell to behave as I would like and I've been searching for an answer for days now.
Summary
Essentially I need to provide tab directory auto-completion as if I was in a different directory to the one I am currently in. It should behave exactly as 'cd' and 'ls' do, but with the starting point in another directory. It seems like such a trivial thing to be able to do but I can't find a way to make it work.
Explanation
Example folder structure below
- root
- foo
- a
- dir1
- subdir1
- dir2
- subdir2
- b
- dir3
- subdir3
- dir4
- subdir4
I am running these scripts whilst in the 'root' directory, but I need tab auto-complete to behave as if I was in the 'foo' directory.
testfunc -d a/dir2/subdir2
Instead of
testfunc -d foo/a/dir2/subdir2
There are a lot of directories inside 'foo' and a lot of sub-directories within them, and this auto-complete behaviour is necessary to speed our process (this script is used extensively throughout the day).
Attempted Solution
I've tried using the 'complete' builtin to get this working by specifying the directory to use, but all this managed to do was auto-complete the first level of directories with a space after the argument instead of continuing to auto-complete like 'cd' would.
complete -x -c testfunc -a "(__fish_complete_directories ./foo/)"
Working bash version
I have already got this working in Bash and I am trying to port it over to fish. See below for the Bash version.
_testfunc()
{
local cur prev words cword
_init_completion || return
compopt +o default
case $prev in
testfunc)
COMPREPLY=( $( compgen -W '-d' -- "$cur" ) )
compopt +o nospace
return
;;
-d)
curdir=$(pwd)
cd foo/ 2>/dev/null && _filedir -d
COMPREPLY=( $( compgen -d -S / -- "$cur" ) )
cd $curdir
return
;;
esac
} &&
complete -o nospace -F _testfunc testfunc
This is essentially stepping into the folder that I want, doing the autocompletion, then stepping back into the original folder that the script was run in. I was hoping this would be easier in Fish after getting it working in Bash (I need to support these two shells), but I'm just pulling my hair out.
Any help would be really appreciated!
I am not a bash completions expert, but it looks like the bash completions are implemented by changing directories, running completions, and then changing back. You can do the same in fish:
function complete_testfunc
set prevdir $PWD
cd foo
__fish_complete_directories
cd $prevdir
end
complete -x -c testfunc -a "(complete_testfunc)"
does that work for you?

Is there any clean way to append an env_file to an autogenerated docker file?

I am planning to self-host Bitwarden using Ansible. During the execution of the ansible playbook, a file hierarchy and a docker-compose file is generated on the remote based on config file parameters and other. At the end, this docker file is executed to spawn the containers.
My personal server infrastructure already servers an nginx-proxy combined with letsencrypt. In order to use this service, I need to add several specific environmental parameters to the "main container" in this docker-compose file. I collected them in an external file and now I need to add a this external file to the docker file. I want to do it dynamically. Until now, I am using the ansible task:
- name: append nginx.env as env file to automatically generated docker file
shell: 'sed -i "\$a\ \ \ \ \ \ - ../env/nginx.env" /srv/bitwarden/bwdata/docker/docker-compose.yml'
to transform:
...
*OTHER CONTAINERS*
...
nginx:
...
*UNIMPORTANT PARAMETERS*
...
env_file:
- ../env/uid.env(EOF)
into
...
*OTHER CONTAINERS*
...
nginx:
...
*UNIMPORTANT PARAMETERS*
...
env_file:
- ../env/uid.env
- ../env/nginx.env(EOF)
But I am unhappy with this sed solution because Bitwarden could modify this auto-generated file (appending to the end would eventually fail.. and I also can't really use any regEx because they could change the structure of single components of the file etc...).
Is there any built-in safe way by ansible to achieve this exact behavior?
EDIT: I am looking for something like:match <container_name> append to env_file <../env/nginx.env>

Coffeescript compile not correctly matching subdirectories

I have the root directory, /. Inside of this, I have x/y.coffee.
Given the following command:
coffee -w -c -o ./ ./
I get this file as output: ./y.js, without the directory.
If I have a subdirectory with more than two characters in its title, the javascript compiles to a subdirectory with the first two characters clipped.
This isn't entirely consistent for example, the ./gesture-panic/x.coffee becomes ./nic/x.js
Weird!
I have reason to believe this may be a fish shell issue.

diff does not work with subdirectories

I want to patch whole directory tree. Although diff finds all differences, patch does apply these to relevant files. When I change a file in subdir I can see patch crate that file one level above it should in the directory tree being patched.
I use command:
diff -Nur extern/ local/ | patch -d extern
what is wrong with that?
Since you're passing -d dir ("Change to the directory dir immediately, before doing anything else.") you also need to tell patch to strip off one level of directories with -p:
diff -Nur extern/ local/ | patch -d extern -p1
That's because diff's output will look something like this:
+++ extern/foo.x
--- local/foo.x
## -21,7 +21,9 ##
- yyy
+ xxx
... so you need to get rid of that first prefix in the path.