04-03-2022
Today I learned that git aliases are case-insensitive – this behavior is documented in http://git-scm.com/docs/git-config#_configuration_file.
The configuration variables are used by both the Git plumbing and the porcelains. The variables are divided into sections, wherein the fully qualified variable name of the variable itself is the last dot-separated segment and the section name is everything before the last dot. The variable names are case-insensitive, allow only alphanumeric characters and -
, and must start with an alphabetic character.
For quite a long time, I noticed a strange behavior in my local git environment (which uses a dotfile config https://github.com/tnguyen14/dotfiles/blob/master/home/.gitconfig). When a branch has not been merged, git would usually shows me a warning like this:
:; git branch -d my-feature-branch
error: The branch 'my-feature-branch' is not fully merged.
If you are sure you want to delete it, run 'git branch -D my-feature-branch'.
I find this behavior helpful, cautioning me against accidentally deleting branches and losing work. Because I do branch deletion often, I add then following config to ~/.gitconfig
:
[alias]
bd = branch -d
However, I started noticing that when I do git bd my-branch
, it would just delete the branch regardless of whether I have the branch changes merged or not. This went on for a while, and eventually it bothered me enough to look into while. I finally figured it out today. This is happening because I have another alias in gitconfig:
[alias]
bd = branch -d
...
bD = branch -D
I suppose that when I was setting up aliases, I was trying to be clever and added a convenient alias for when I do want to force-delete the branch. As aliases are case-sensitive, the latter one (branch -D
) wins and is always used whenever I type git bd
.
12-02-2021
When I had to bring up a Windows Server on AWS using the default Windows Server AMI recently, I needed a way to automatically configure the machine so it can be SSH-ed into without manual configuration. This was needed in order to run ansible on the machine after it was brought up by Terraform.
This could be done with cloud-init and a PowerShell script. The script would install OpenSSH server and configure the permissions for the authorized_keys
file to allow incoming SSH session for the Administrator
user.
<powershell>
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'
$AuthorizedKeyFile = 'C:\ProgramData\ssh\administrators_authorized_keys'
New-Item $AuthorizedKeyFile
Set-Content $AuthorizedKeyFile '${authorized_keys}'
# Reset authorized_keys file ACL to enable SSH
# By default, it inherits parent folder permission, which is too permissive
$Acl = Get-Acl -Path $AuthorizedKeyFile
# disable inheritance
$isProtected = $true
$preserveInheritance = $false
$Acl.SetAccessRuleProtection($isProtected, $preserveInheritance)
$Administrators = 'BUILTIN\Administrators'
$System = 'SYSTEM'
$FullControl = 'FullControl'
$AdministratorAccessRule = New-Object Security.AccessControl.FileSystemAccessRule $Administrators, $FullControl, 'Allow'
$SystemAccessRule = New-Object Security.AccessControl.FileSystemAccessRule $System, $FullControl, 'Allow'
$Acl.SetAccessRule($AdministratorAccessRule)
$Acl.SetAccessRule($SystemAccessRule)
Set-Acl -Path $AuthorizedKeyFile -AclObject $Acl
</powershell>
The local machine’s public SSH key is added to authorized_keys
file as a template parameter.
06-10-2021
Learning how to use styles with react-native
I’ve learned that in order to apply styles to react-native, I would use StyleSheet
as such:
// src/components/Header.jsx
import React from 'react';
import { StyleSheet, View, Text } from 'react-native';
function Header() {
return (
<View>
<Text style={styles.heading}>Heading</Text>
</View>
)
}
const styles = StyleSheet.create({
heading: {
fontSize: 20,
textAlign: 'center'
}
})
In keeping with my goal of reusing as much of the existing app as possible, I want to use Bootstrap for basic styles. This can be achieved with StyleSheet.compose
. (I’m also splitting the styles into its own module.)
// src/components/Header.jsx
import React from 'react';
import { View, Text } from 'react-native';
import styles from './Header.style.js';
function Header() {
return (
<View>
<Text style={styles.heading}>Heading</Text>
</View>
)
}
// src/components/Header.style.js
import { StyleSheet } from 'react-native';
import BootstrapStyleSheet from 'react-native-bootstrap-styles';
const { bs } = new BootsrtapStyleSheet();
const styles = StyleSheet.create({
heading: {
fontSize: 20,
textAlign: 'center'
}
});
export default {
...styles,
heading: StyleSheet.compose(bs.s1, styles.heading)
}
So far, it’s pretty straightforward.
Next, I want to use CSS features such as rem
units and custom properties, in order to keep the native design as consistent with the web design as possible. From some searching around, the way to use those features is with react-native-extended-stylesheet
. A simple example of its usage would look like so:
// src/components/Header.jsx
import React from 'react';
import { View, Text } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet';
function Header() {
return (
<View>
<Text style={styles.heading}>Heading</Text>
</View>
)
}
const styles = EStyleSheet.create({
heading: {
fontSize: '1.5rem',
color: '$colorGreen'
}
});
// src/index.jsx
import EStyleSheet from 'react-native-extended-stylesheet';
EStyleSheet.build({
$rem: 16,
$colorGreen: '#4caf50'
});
The EStyleSheet.build()
is important to to define the variables, as well as “calculate” the stylesheets. However, because of that step, we can’t use EStyleSheet
as a drop-in replacement for StyleSheet
when it comes to style composition. At import time, the styles have not been “calculated” yet.
// This does NOT work
// src/components/Header.style.js
import { StyleSheet } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet';
import BootstrapStyleSheet from 'react-native-bootstrap-styles';
const { bs } = new BootsrtapStyleSheet();
const styles = EStyleSheet.create({
heading: {
fontSize: '1.5rem',
color: '$colorGreen'
}
});
export default {
...styles,
heading: StyleSheet.compose(bs.s1, styles.heading)
}
In order to combine extended stylesheet with bootstrap styles, the styles need to be dynamically generated at component runtime:
// src/components/Header.jsx
import React from 'react'
import { View, Text } from 'react-native';
import getStyles from './Header.style.js';
function Header() {
const styles = getStyles();
return (
<View>
<Text style={styles.heading}>Heading</Text>
</View>
)
}
// src/components/Header.style.js
import { StyleSheet } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet';
import BootstrapStyleSheet from 'react-native-bootstrap-styles';
const { bs } = new BootstrapStyleSheet();
const styles = EStyleSheet.create({
heading: {
fontSize: '1.5rem',
color: '$colorGreen'
}
});
export default function () {
return {
...styles,
heading: StyleSheet.compose(bs.h1, styles.heading)
}
}
There is a bit more wrapping layers in this workaround, but it achieves the goal of keeping the styles consistent with the usage of Bootstrap and CSS features.
06-03-2021
I am adding an Android native version to a React app I’m maintaining as an attempt to learn react-native. I currently know next to nothing about react-native or native development, even though two of my closest friends are native and react-native developers.
Hopefully this exercise will provide me with an opportunity to be more informed about building a user experience that feels more native. As a strong believer in the web, I am a little apprehensive about this endeavor. I suspect there will be concepts that I find “weird” or difficult to wrap my head around, especially around CSS and layouts.
I also worry that this will add a major burden of maintenance for this app. Every new change will need to be done in the web version first, and require another pass to make it work the same for native. I am aware of react-native-web
, but I doubt it is something I would consider seriously. I still very much enjoy using “native” web constructs.
Going into this exercise, I have a couple of high-level goals.
- Reuse as much of the existing source code as possible.
- Keep the structure of native code as much in parallel to the web counterpart.
Not knowing much about react-native, I am not sure if these are realistic. At this moment, I am quite insistent on the first goal, as it would be “the whole point” of react-native for me. The elusive idea of “write once, run everywhere”. Granted, much of the component markup/ CSS would not be reusable. I am hoping that the redux stuff, such as reducers and actions, or selectors, could be used wholesale. They contain a significant portion of the “business logic”, and it would be hugely beneficial to not have to rewrite them. There are logic embedded in the components as well, though it’s unclear to me whether they can be shared between web and native at this point.
The second goal is really about reducing the aforementioned maintenance burden. The more similar/ in parallel the web and native code are, the easier it would be to implement features for both.
I will be documenting weird hacks and mistakes along the way. There will be plenty.