Skip to content

Commit

Permalink
Merge branch 'master' into install-some-software
Browse files Browse the repository at this point in the history
  • Loading branch information
joshaber committed Sep 8, 2017
2 parents 7862392 + 170142a commit 800287e
Show file tree
Hide file tree
Showing 35 changed files with 1,479 additions and 360 deletions.
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"productName": "GitHub Desktop",
"bundleID": "com.github.GitHubClient",
"companyName": "GitHub, Inc.",
"version": "0.8.1-beta3",
"version": "0.8.1",
"main": "./main.js",
"repository": {
"type": "git",
Expand Down
19 changes: 18 additions & 1 deletion app/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export interface IAPIUser {
readonly login: string
readonly avatar_url: string
readonly name: string
readonly type: 'User' | 'Organization'
}

/** The users we get from the mentionables endpoint. */
Expand Down Expand Up @@ -210,6 +211,18 @@ export class API {
}
}

/** Fetch all repos a user has access to. */
public async fetchRepositories(): Promise<ReadonlyArray<
IAPIRepository
> | null> {
try {
return await this.fetchAll<IAPIRepository>('user/repos')
} catch (error) {
log.warn(`fetchRepositories: ${error}`)
return null
}
}

/** Fetch the logged in account. */
public async fetchAccount(): Promise<IAPIUser> {
try {
Expand Down Expand Up @@ -352,7 +365,11 @@ export class API {
*/
private async fetchAll<T>(path: string): Promise<ReadonlyArray<T>> {
const buf = new Array<T>()
let nextPath: string | null = path

const params = {
per_page: '100',
}
let nextPath: string | null = urlWithQueryString(path, params)

do {
const response = await this.request('GET', nextPath)
Expand Down
12 changes: 11 additions & 1 deletion app/src/lib/app-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { RetryAction } from './retry-actions'
import { ExternalEditor } from '../models/editors'
import { PreferencesTab } from '../models/preferences'
import { Shell } from './shells'
import { CloneRepositoryTab } from '../models/clone-repository-tab'

export { ICommitMessage }
export { IAheadBehind }
Expand Down Expand Up @@ -160,6 +161,12 @@ export interface IAppState {

/** The user's preferred shell. */
readonly selectedShell: Shell

/** The current repository filter text. */
readonly repositoryFilterText: string

/** The currently selected tab for Clone Repository. */
readonly selectedCloneRepositoryTab: CloneRepositoryTab
}

export enum PopupType {
Expand Down Expand Up @@ -202,7 +209,10 @@ export type Popup =
| { type: PopupType.RepositorySettings; repository: Repository }
| { type: PopupType.AddRepository; path?: string }
| { type: PopupType.CreateRepository; path?: string }
| { type: PopupType.CloneRepository; initialURL: string | null }
| {
type: PopupType.CloneRepository
initialURL: string | null
}
| { type: PopupType.CreateBranch; repository: Repository }
| { type: PopupType.SignIn }
| { type: PopupType.About }
Expand Down
22 changes: 22 additions & 0 deletions app/src/lib/dispatcher/app-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ import {
isUsingLFS,
installLFSHooks,
} from '../git/lfs'
import { CloneRepositoryTab } from '../../models/clone-repository-tab'

const LastSelectedRepositoryIDKey = 'last-selected-repository-id'

Expand Down Expand Up @@ -196,13 +197,18 @@ export class AppStore {
/** The user's preferred shell. */
private selectedShell = DefaultShell

/** The current repository filter text */
private repositoryFilterText: string = ''

private readonly statsStore: StatsStore

/** The function to resolve the current Open in Desktop flow. */
private resolveOpenInDesktop:
| ((repository: Repository | null) => void)
| null = null

private selectedCloneRepositoryTab: CloneRepositoryTab = CloneRepositoryTab.DotCom

public constructor(
gitHubUserStore: GitHubUserStore,
cloningRepositoriesStore: CloningRepositoriesStore,
Expand Down Expand Up @@ -500,6 +506,8 @@ export class AppStore {
selectedExternalEditor: this.selectedExternalEditor,
imageDiffType: this.imageDiffType,
selectedShell: this.selectedShell,
repositoryFilterText: this.repositoryFilterText,
selectedCloneRepositoryTab: this.selectedCloneRepositoryTab,
}
}

Expand Down Expand Up @@ -668,6 +676,12 @@ export class AppStore {
this.emitUpdate()
}

/** This shouldn't be called directly. See `Dispatcher`. */
public async _setRepositoryFilterText(text: string): Promise<void> {
this.repositoryFilterText = text
this.emitUpdate()
}

/** This shouldn't be called directly. See `Dispatcher`. */
public async _changeHistoryFileSelection(
repository: Repository,
Expand Down Expand Up @@ -2615,4 +2629,12 @@ export class AppStore {
}
}
}

public _changeCloneRepositoriesTab(tab: CloneRepositoryTab): Promise<void> {
this.selectedCloneRepositoryTab = tab

this.emitUpdate()

return Promise.resolve()
}
}
17 changes: 16 additions & 1 deletion app/src/lib/dispatcher/dispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { installCLI } from '../../ui/lib/install-cli'
import * as GenericGitAuth from '../generic-git-auth'
import { RetryAction, RetryActionType } from '../retry-actions'
import { Shell } from '../shells'
import { CloneRepositoryTab } from '../../models/clone-repository-tab'

/**
* An error handler function.
Expand Down Expand Up @@ -146,6 +147,11 @@ export class Dispatcher {
return this.appStore._changeHistoryFileSelection(repository, file)
}

/** Set the repository filter text. */
public setRepositoryFilterText(text: string): Promise<void> {
return this.appStore._setRepositoryFilterText(text)
}

/** Select the repository. */
public selectRepository(
repository: Repository | CloningRepository
Expand Down Expand Up @@ -910,7 +916,11 @@ export class Dispatcher {
return this.checkoutBranch(repo, branch)
} else {
return this.appStore._startOpenInDesktop(() => {
this.showPopup({ type: PopupType.CloneRepository, initialURL: url })
this.changeCloneRepositoriesTab(CloneRepositoryTab.Generic)
this.showPopup({
type: PopupType.CloneRepository,
initialURL: url,
})
})
}
}
Expand Down Expand Up @@ -987,4 +997,9 @@ export class Dispatcher {
): Promise<void> {
return this.appStore._installLFSHooks(repositories)
}

/** Change the selected Clone Repository tab. */
public changeCloneRepositoriesTab(tab: CloneRepositoryTab): Promise<void> {
return this.appStore._changeCloneRepositoriesTab(tab)
}
}
16 changes: 16 additions & 0 deletions app/src/lib/feature-flag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Enables the application to opt-in for preview features based on runtime
* checks. This is backed by the GITHUB_DESKTOP_PREVIEW_FEATURES environment
* variable, which is checked for non-development environments.
*/
export function enablePreviewFeatures(): boolean {
if (__DEV__) {
return true
}

if (process.env.GITHUB_DESKTOP_PREVIEW_FEATURES) {
return true
}

return false
}
1 change: 0 additions & 1 deletion app/src/lib/menu-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ function getMenuState(state: IAppState): Map<MenuIDs, IMenuItemState> {
'create-branch',
'show-changes',
'show-history',
'show-repository-list',
'show-branches-list',
'open-external-editor',
]
Expand Down
120 changes: 78 additions & 42 deletions app/src/lib/registry.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import * as Path from 'path'
import { pathExists } from './file-system'

import { spawn } from 'child_process'
import { getActiveCodePage } from './shell'

// This is a stripped back version of winreg:
// https://github.com/fresc81/node-winreg
Expand All @@ -8,30 +11,60 @@ import { spawn } from 'child_process'
// the keys found by `reg.exe`, and rather than trying to fix and potentially
// regress other parts I've extracted just the bit that I need to use.

const windir = process.env.windir || 'C:\\Windows'
const regPath = Path.join(windir, 'System32', 'reg.exe')

const ITEM_PATTERN = /^(.*)\s(REG_SZ|REG_MULTI_SZ|REG_EXPAND_SZ|REG_DWORD|REG_QWORD|REG_BINARY|REG_NONE)\s+([^\s].*)$/

export interface IRegistryEntry {
readonly name: string
readonly type: string
readonly value: string
}

/**
* Read registry keys found at the expected location.
*
* This method will return an empty list if the expected key does not exist,
* instead of throwing an error.
*
* @param key The registry key to lookup
*/
export function readRegistryKeySafe(
key: string
const ITEM_PATTERN = /^(.*)\s(REG_SZ|REG_MULTI_SZ|REG_EXPAND_SZ|REG_DWORD|REG_QWORD|REG_BINARY|REG_NONE)\s+([^\s].*)$/

function parse(output: string): ReadonlyArray<IRegistryEntry> {
const lines = output.split('\n')

const items = []
const results = new Array<IRegistryEntry>()
let lineNumber = 0

for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim()
if (line.length > 0) {
if (lineNumber !== 0) {
items.push(line)
}
++lineNumber
}
}

for (let i = 0; i < items.length; i++) {
const match = ITEM_PATTERN.exec(items[i])
if (match) {
const name = match[1].trim()
const type = match[2].trim()
const value = match[3]
results.push({ name, type, value })
}
}

return results
}

function getPathToBatchFile(): string {
if (process.env.TEST_ENV) {
return Path.join(__dirname, '..', '..', 'static', 'win32', 'registry.bat')
} else {
return Path.join(__dirname, 'static', 'registry.bat')
}
}

const batchFilePath = getPathToBatchFile()

function readRegistry(
key: string,
activeCodePage: number
): Promise<ReadonlyArray<IRegistryEntry>> {
return new Promise<ReadonlyArray<IRegistryEntry>>((resolve, reject) => {
const proc = spawn(regPath, ['QUERY', key], {
const proc = spawn(batchFilePath, [key, activeCodePage.toString()], {
cwd: undefined,
})

Expand All @@ -45,32 +78,7 @@ export function readRegistryKeySafe(
resolve([])
} else {
const output = Buffer.concat(buffers).toString('utf8')
const lines = output.split('\n')

const items = []
const results = new Array<IRegistryEntry>()
let lineNumber = 0

for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim()
if (line.length > 0) {
if (lineNumber !== 0) {
items.push(line)
}
++lineNumber
}
}

for (let i = 0; i < items.length; i++) {
const match = ITEM_PATTERN.exec(items[i])
if (match) {
const name = match[1].trim()
const type = match[2].trim()
const value = match[3]
results.push({ name, type, value })
}
}

const results = parse(output)
resolve(results)
}
})
Expand All @@ -85,3 +93,31 @@ export function readRegistryKeySafe(
})
})
}

/**
* Read registry keys found at the expected location.
*
* This method will return an empty list if the expected key does not exist,
* instead of throwing an error.
*
* @param key The registry key to lookup
*/
export async function readRegistryKeySafe(
key: string
): Promise<ReadonlyArray<IRegistryEntry>> {
const exists = await pathExists(batchFilePath)
if (!exists) {
log.error(
`Unable to find batch script at expected location: '${batchFilePath}'`
)
return []
}

const activeCodePage = await getActiveCodePage()
if (!activeCodePage) {
log.debug('Unable to resolve active code page')
return []
}

return await readRegistry(key, activeCodePage)
}
Loading

0 comments on commit 800287e

Please sign in to comment.