diff --git a/compiler/ast.nim b/compiler/ast.nim index f93c8d9101..b5306c423c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -510,7 +510,7 @@ type nfLastRead # this node is a last read nfFirstWrite # this node is a first write nfHasComment # node has a comment - nfUseDefaultField # node has a default value (object constructor) + nfSkipFieldChecking # node skips field visable checking TNodeFlags* = set[TNodeFlag] TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 46) @@ -1081,7 +1081,7 @@ const nfIsRef, nfIsPtr, nfPreventCg, nfLL, nfFromTemplate, nfDefaultRefsParam, nfExecuteOnReload, nfLastRead, - nfFirstWrite, nfUseDefaultField} + nfFirstWrite, nfSkipFieldChecking} namePos* = 0 patternPos* = 1 # empty except for term rewriting macros genericParamsPos* = 2 diff --git a/compiler/sem.nim b/compiler/sem.nim index 48a7d56c8a..1c15f905e3 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -572,7 +572,7 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): s let asgnExpr = defaultNodeField(c, recNode, recNode.typ) if asgnExpr != nil: hasDefault = true - asgnExpr.flags.incl nfUseDefaultField + asgnExpr.flags.incl nfSkipFieldChecking result.add newTree(nkExprColonExpr, recNode, asgnExpr) return @@ -582,7 +582,7 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): s newSymNode(getSysMagic(c.graph, recNode.info, "zeroDefault", mZeroDefault)), newNodeIT(nkType, recNode.info, asgnType) ) - asgnExpr.flags.incl nfUseDefaultField + asgnExpr.flags.incl nfSkipFieldChecking asgnExpr.typ = recType result.add newTree(nkExprColonExpr, recNode, asgnExpr) else: @@ -604,7 +604,7 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] = defaultValue = newIntNode(nkIntLit#[c.graph]#, 0) defaultValue.typ = discriminator.typ selectedBranch = recNode.pickCaseBranchIndex defaultValue - defaultValue.flags.incl nfUseDefaultField + defaultValue.flags.incl nfSkipFieldChecking result.add newTree(nkExprColonExpr, discriminator, defaultValue) result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1]) of nkSym: @@ -616,7 +616,7 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] = let asgnExpr = defaultNodeField(c, recNode, recType) if asgnExpr != nil: asgnExpr.typ = recType - asgnExpr.flags.incl nfUseDefaultField + asgnExpr.flags.incl nfSkipFieldChecking result.add newTree(nkExprColonExpr, recNode, asgnExpr) else: doAssert false diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 54f03026f8..987fd4a13b 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -338,7 +338,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = if n[0].kind in nkIdentKinds: let ident = considerQuotedIdent(c, n[0], n).s localError(c.config, n.info, errUndeclaredRoutine % ident) - else: + else: localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree) return @@ -630,7 +630,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, if efExplain notin flags: # repeat the overload resolution, # this time enabling all the diagnostic output (this should fail again) - discard semOverloadedCall(c, n, nOrig, filter, flags + {efExplain}) + result = semOverloadedCall(c, n, nOrig, filter, flags + {efExplain}) elif efNoUndeclared notin flags: notFoundError(c, n, errors) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 173f011a80..ee21e08767 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -302,7 +302,7 @@ proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode = result = newNodeI(nkConv, n.info) var targetType = semTypeNode(c, n[0], nil) - case targetType.kind + case targetType.skipTypes({tyDistinct}).kind of tyTypeDesc: internalAssert c.config, targetType.len > 0 if targetType.base.kind == tyNone: @@ -787,7 +787,7 @@ proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode = else: result = newHiddenAddrTaken(c, n, isOutParam) -proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = +proc analyseIfAddressTakenInCall(c: PContext, n: PNode, isConverter = false) = checkMinSonsLen(n, 1, c.config) const FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl, @@ -795,10 +795,15 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy, mMove, mWasMoved} + template checkIfConverterCalled(c: PContext, n: PNode) = + ## Checks if there is a converter call which wouldn't be checked otherwise + # Call can sometimes be wrapped in a deref + let node = if n.kind == nkHiddenDeref: n[0] else: n + if node.kind == nkHiddenCallConv: + analyseIfAddressTakenInCall(c, node, true) # get the real type of the callee # it may be a proc var with a generic alias type, so we skip over them var t = n[0].typ.skipTypes({tyGenericInst, tyAlias, tySink}) - if n[0].kind == nkSym and n[0].sym.magic in FakeVarParams: # BUGFIX: check for L-Value still needs to be done for the arguments! # note sometimes this is eval'ed twice so we check for nkHiddenAddr here: @@ -813,6 +818,8 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = discard "allow access within a cast(unsafeAssign) section" else: localError(c.config, it.info, errVarForOutParamNeededX % $it) + # Make sure to still check arguments for converters + c.checkIfConverterCalled(n[i]) # bug #5113: disallow newSeq(result) where result is a 'var T': if n[0].sym.magic in {mNew, mNewFinalize, mNewSeq}: var arg = n[1] #.skipAddr @@ -824,15 +831,14 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = return for i in 1..", sideEffect.} -when defined(linux) or defined(bsd): +when defined(linux) or defined(bsd) or defined(nuttx): proc accept4*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr SockLen, flags: cint): SocketHandle {.importc, header: "".} diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 1b6734b518..ea8731405d 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -10,7 +10,7 @@ when defined(nimHasStyleChecks): {.push styleChecks: off.} -when defined(freertos) or defined(zephyr) or defined(nuttx): +when defined(freertos) or defined(zephyr): const hasSpawnH = false # should exist for every Posix system nowadays hasAioH = false @@ -646,7 +646,7 @@ elif defined(nuttx): else: var SO_REUSEPORT* {.importc, header: "".}: cint -when defined(linux) or defined(bsd): +when defined(linux) or defined(bsd) or defined(nuttx): var SOCK_CLOEXEC* {.importc, header: "".}: cint when defined(macosx): @@ -675,14 +675,14 @@ when defined(haiku): when hasSpawnH: when defined(linux): - # better be safe than sorry; Linux has this flag, macosx doesn't, don't - # know about the other OSes + # better be safe than sorry; Linux has this flag, macosx and NuttX don't, + # don't know about the other OSes - # Non-GNU systems like TCC and musl-libc don't define __USE_GNU, so we + # Non-GNU systems like TCC and musl-libc don't define __USE_GNU, so we # can't get the magic number from spawn.h const POSIX_SPAWN_USEVFORK* = cint(0x40) else: - # macosx lacks this, so we define the constant to be 0 to not affect + # macosx and NuttX lack this, so we define the constant to be 0 to not affect # OR'ing of flags: const POSIX_SPAWN_USEVFORK* = cint(0) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 1773e827b1..bcdd0879d6 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -1077,9 +1077,9 @@ template newSeqWith*(len: int, init: untyped): untyped = import std/random var seqRand = newSeqWith(20, rand(1.0)) assert seqRand[0] != seqRand[1] - - var result = newSeq[typeof(init)](len) - for i in 0 ..< len: + let newLen = len + var result = newSeq[typeof(init)](newLen) + for i in 0 ..< newLen: result[i] = init move(result) # refs bug #7295 diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index d2cf64149f..fd0ef38564 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -10,6 +10,8 @@ ## This module implements a simple HTTP client that can be used to retrieve ## webpages and other data. ## +## .. warning:: Validate untrusted inputs: URI parsers and getters are not detecting malicious URIs. +## ## Retrieving a website ## ==================== ## diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 915337f122..e30f1da737 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -1053,13 +1053,15 @@ elif not defined(useNimRtl): var mask: Sigset chck sigemptyset(mask) chck posix_spawnattr_setsigmask(attr, mask) - if poDaemon in data.options: - chck posix_spawnattr_setpgroup(attr, 0'i32) + when not defined(nuttx): + if poDaemon in data.options: + chck posix_spawnattr_setpgroup(attr, 0'i32) var flags = POSIX_SPAWN_USEVFORK or POSIX_SPAWN_SETSIGMASK - if poDaemon in data.options: - flags = flags or POSIX_SPAWN_SETPGROUP + when not defined(nuttx): + if poDaemon in data.options: + flags = flags or POSIX_SPAWN_SETPGROUP chck posix_spawnattr_setflags(attr, flags) if not (poParentStreams in data.options): diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index ebc8b90efb..725d5bbd95 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -14,6 +14,8 @@ ## as a locator, a name, or both. The term "Uniform Resource Locator" ## (URL) refers to the subset of URIs. ## +## .. warning:: URI parsers in this module do not perform security validation. +## ## # Basic usage diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 82513bc984..186da4df81 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -190,7 +190,7 @@ proc text*(n: XmlNode): lent string {.inline.} = assert $c == "" assert c.text == "my comment" - n.expect {xnText, xnComment, xnCData, xnEntity} + n.expect {xnText, xnVerbatimText, xnComment, xnCData, xnEntity} result = n.fText proc `text=`*(n: XmlNode, text: sink string) {.inline.} = @@ -208,7 +208,7 @@ proc `text=`*(n: XmlNode, text: sink string) {.inline.} = e.text = "a new entity text" assert $e == "&a new entity text;" - n.expect {xnText, xnComment, xnCData, xnEntity} + n.expect {xnText, xnVerbatimText, xnComment, xnCData, xnEntity} n.fText = text proc tag*(n: XmlNode): lent string {.inline.} = @@ -735,7 +735,7 @@ proc addImpl(result: var string, n: XmlNode, indent = 0, indWidth = 2, addNewLines = true, lastNodeIsText = false) = proc noWhitespace(n: XmlNode): bool = for i in 0 ..< n.len: - if n[i].kind in {xnText, xnEntity}: return true + if n[i].kind in {xnText, xnVerbatimText, xnEntity}: return true proc addEscapedAttr(result: var string, s: string) = # `addEscaped` alternative with less escaped characters. @@ -784,7 +784,7 @@ proc addImpl(result: var string, n: XmlNode, indent = 0, indWidth = 2, var lastNodeIsText = false for i in 0 ..< n.len: result.addImpl(n[i], indentNext, indWidth, addNewLines, lastNodeIsText) - lastNodeIsText = n[i].kind == xnText + lastNodeIsText = (n[i].kind == xnText) or (n[i].kind == xnVerbatimText) if not n.noWhitespace(): result.addIndent(indent, addNewLines) diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index cee70f6774..ac1741ceb5 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -268,6 +268,20 @@ proc getMaxMem(a: var MemRegion): int = # maximum of these both values here: result = max(a.currMem, a.maxMem) +const nimMaxHeap {.intdefine.} = 0 + +proc allocPages(a: var MemRegion, size: int): pointer = + when nimMaxHeap != 0: + if a.occ + size > nimMaxHeap * 1024 * 1024: + raiseOutOfMem() + osAllocPages(size) + +proc tryAllocPages(a: var MemRegion, size: int): pointer = + when nimMaxHeap != 0: + if a.occ + size > nimMaxHeap * 1024 * 1024: + raiseOutOfMem() + osTryAllocPages(size) + proc llAlloc(a: var MemRegion, size: int): pointer = # *low-level* alloc for the memory managers data structures. Deallocation # is done at the end of the allocator's life time. @@ -277,7 +291,7 @@ proc llAlloc(a: var MemRegion, size: int): pointer = # is one page: sysAssert roundup(size+sizeof(LLChunk), PageSize) == PageSize, "roundup 6" var old = a.llmem # can be nil and is correct with nil - a.llmem = cast[PLLChunk](osAllocPages(PageSize)) + a.llmem = cast[PLLChunk](allocPages(a, PageSize)) when defined(nimAvlcorruption): trackLocation(a.llmem, PageSize) incCurrMem(a, PageSize) @@ -453,15 +467,10 @@ when false: it, it.next, it.prev, it.size) it = it.next -const nimMaxHeap {.intdefine.} = 0 - proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = when not defined(emscripten): if not a.blockChunkSizeIncrease: let usedMem = a.occ #a.currMem # - a.freeMem - when nimMaxHeap != 0: - if usedMem > nimMaxHeap * 1024 * 1024: - raiseOutOfMem() if usedMem < 64 * 1024: a.nextChunkSize = PageSize*4 else: @@ -470,11 +479,11 @@ proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = var size = size if size > a.nextChunkSize: - result = cast[PBigChunk](osAllocPages(size)) + result = cast[PBigChunk](allocPages(a, size)) else: - result = cast[PBigChunk](osTryAllocPages(a.nextChunkSize)) + result = cast[PBigChunk](tryAllocPages(a, a.nextChunkSize)) if result == nil: - result = cast[PBigChunk](osAllocPages(size)) + result = cast[PBigChunk](allocPages(a, size)) a.blockChunkSizeIncrease = true else: size = a.nextChunkSize @@ -654,7 +663,7 @@ proc getBigChunk(a: var MemRegion, size: int): PBigChunk = releaseSys a.lock proc getHugeChunk(a: var MemRegion; size: int): PBigChunk = - result = cast[PBigChunk](osAllocPages(size)) + result = cast[PBigChunk](allocPages(a, size)) when RegionHasLock: if not a.lockActive: a.lockActive = true @@ -811,9 +820,9 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer = sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken") var size = roundup(requestedSize, MemAlign) sysAssert(size >= sizeof(FreeCell), "rawAlloc: requested size too small") - sysAssert(size >= requestedSize, "insufficient allocated size!") #c_fprintf(stdout, "alloc; size: %ld; %ld\n", requestedSize, size) + if size <= SmallChunkSize-smallChunkOverhead(): # allocate a small block: for small chunks, we use only its next pointer let s = size div MemAlign diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index 54c51e7838..eb08845603 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -391,7 +391,6 @@ else: let regEnd = sp +% sizeof(registers) while sp <% regEnd: gcMark(gch, cast[PPointer](sp)[]) - gcMark(gch, cast[PPointer](sp +% sizeof(pointer) div 2)[]) sp = sp +% sizeof(pointer) # Make sure sp is word-aligned sp = sp and not (sizeof(pointer) - 1) diff --git a/nim.nimble b/nim.nimble index 380ffbce8f..b0253f66d5 100644 --- a/nim.nimble +++ b/nim.nimble @@ -10,6 +10,8 @@ skipDirs = @["build" , "changelogs" , "ci" , "csources_v2" , "drnim" , "nimdoc", before install: when defined(windows): - exec "build_all.bat" + if not "bin\nim.exe".fileExists: + exec "build_all.bat" else: - exec "./build_all.sh" + if not "bin/nim".fileExists: + exec "./build_all.sh" diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index ce9681975a..685dbedb8d 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -234,7 +234,7 @@ proc executeNoHooks(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int, localError(conf, conf.m.trackPos, "found no symbol at this position " & (conf $ conf.m.trackPos)) proc executeNoHooks(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int, graph: ModuleGraph) = - executeNoHooks(cmd, file, dirtyfile, line, col, graph) + executeNoHooks(cmd, file, dirtyfile, line, col, "", graph) proc execute(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int; tag: string, graph: ModuleGraph) = diff --git a/tests/arc/t20588.nim b/tests/arc/t20588.nim index d747c656d3..008bd1dcd3 100644 --- a/tests/arc/t20588.nim +++ b/tests/arc/t20588.nim @@ -5,6 +5,7 @@ discard """ t20588.nim(20, 12) Error: illegal type conversion to 'auto' t20588.nim(21, 14) Error: illegal type conversion to 'typed' t20588.nim(22, 16) Error: illegal type conversion to 'untyped' +t20588.nim(24, 7) Error: illegal type conversion to 'any' ''' """ @@ -16,7 +17,9 @@ t20588.nim(22, 16) Error: illegal type conversion to 'untyped' - discard 0.0.auto discard typed("abc") discard untyped(4) +var a = newSeq[bool](1000) +if any(a): + echo "ok?" \ No newline at end of file diff --git a/tests/converter/t21531.nim b/tests/converter/t21531.nim new file mode 100644 index 0000000000..b0198684d7 --- /dev/null +++ b/tests/converter/t21531.nim @@ -0,0 +1,10 @@ +import std/typetraits + +type Foo* = distinct string + +converter toBase*(headers: var Foo): var string = + headers.distinctBase + +proc bar*(headers: var Foo) = + for x in headers: discard + diff --git a/tests/generics/m3770.nim b/tests/generics/m3770.nim new file mode 100644 index 0000000000..2c6a2bd113 --- /dev/null +++ b/tests/generics/m3770.nim @@ -0,0 +1,6 @@ +type + Noice* = object + hidden: int + +template jjj*: Noice = + Noice(hidden: 15) \ No newline at end of file diff --git a/tests/generics/t3770.nim b/tests/generics/t3770.nim new file mode 100644 index 0000000000..fa9c97df83 --- /dev/null +++ b/tests/generics/t3770.nim @@ -0,0 +1,9 @@ +# bug #3770 +import m3770 + +doAssert $jjj() == "(hidden: 15)" # works + +proc someGeneric(_: type) = + doAssert $jjj() == "(hidden: 15)" # fails: "Error: the field 'hidden' is not accessible." + +someGeneric(int) diff --git a/tests/stdlib/tsequtils.nim b/tests/stdlib/tsequtils.nim index 176c00214b..2b9ef5d6ea 100644 --- a/tests/stdlib/tsequtils.nim +++ b/tests/stdlib/tsequtils.nim @@ -388,6 +388,11 @@ block: # newSeqWith tests seq2D[0][1] = true doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]] +block: # bug #21538 + var x: seq[int] = @[2, 4] + var y = newSeqWith(x.pop(), true) + doAssert y == @[true, true, true, true] + block: # mapLiterals tests let x = mapLiterals([0.1, 1.2, 2.3, 3.4], int) doAssert x is array[4, int] diff --git a/tests/stdlib/txmltree.nim b/tests/stdlib/txmltree.nim index 4362f5ec32..c878715445 100644 --- a/tests/stdlib/txmltree.nim +++ b/tests/stdlib/txmltree.nim @@ -99,3 +99,18 @@ block: # bug #21290 doAssert s == """ Hola """ + +block: #21541 + let root = <>root() + root.add <>child(newText("hello")) + root.add <>more(newVerbatimText("hola")) + let s = $root + doAssert s == """ + hello + hola +""" + + let temp = newVerbatimText("Hello!") + doAssert temp.text == "Hello!" + temp.text = "Hola!" + doAssert temp.text == "Hola!" diff --git a/tools/atlas/atlas.md b/tools/atlas/atlas.md index ee770cd626..61ca28ff00 100644 --- a/tools/atlas/atlas.md +++ b/tools/atlas/atlas.md @@ -79,3 +79,9 @@ in its description (or name or list of tags). ### Install Use the .nimble file to setup the project's dependencies. + +### Update [filter] + +Update every package in the workspace that has a remote URL that +matches `filter` if a filter is given. The package is only updated +if there are no uncommitted changes. diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index 274e94517e..dfa60856ef 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -9,9 +9,11 @@ ## Simple tool to automate frequent workflows: Can "clone" ## a Nimble dependency and its dependencies recursively. -import std/[parseopt, strutils, os, osproc, unicode, tables, sets, json, jsonutils] +import std/[parseopt, strutils, os, osproc, tables, sets, json, jsonutils] import parse_requires, osutils, packagesjson +from unicode import nil + const Version = "0.2" Usage = "atlas - Nim Package Cloner Version " & Version & """ @@ -25,6 +27,8 @@ Command: search keyw keywB... search for package that contains the given keywords extract file.nimble extract the requirements and custom commands from the given Nimble file + update [filter] update every package in the workspace that has a remote + URL that matches `filter` if a filter is given Options: --keepCommits do not perform any `git checkouts` @@ -146,7 +150,7 @@ proc toDepRelation(s: string): DepRelation = of ">": strictlyGreater else: normal -proc isCleanGit(c: var AtlasContext; dir: string): string = +proc isCleanGit(c: var AtlasContext): string = result = "" let (outp, status) = exec(c, GitDiff, []) if outp.len != 0: @@ -264,7 +268,7 @@ proc checkoutCommit(c: var AtlasContext; w: Dependency) = if w.commit.len == 0 or cmpIgnoreCase(w.commit, "head") == 0: gitPull(c, w.name) else: - let err = isCleanGit(c, dir) + let err = isCleanGit(c) if err != "": warn c, w.name, err else: @@ -448,6 +452,27 @@ proc installDependencies(c: var AtlasContext; nimbleFile: string) = let paths = cloneLoop(c, work) patchNimCfg(c, paths, if c.cfgHere: getCurrentDir() else: findSrcDir(c)) +proc updateWorkspace(c: var AtlasContext; filter: string) = + for kind, file in walkDir(c.workspace): + if kind == pcDir and dirExists(file / ".git"): + c.withDir file: + let pkg = PackageName(file) + let (remote, _) = osproc.execCmdEx("git remote -v") + if filter.len == 0 or filter in remote: + let diff = isCleanGit(c) + if diff != "": + warn(c, pkg, "has uncommitted changes; skipped") + else: + let (branch, _) = osproc.execCmdEx("git rev-parse --abbrev-ref HEAD") + if branch.strip.len > 0: + let (output, exitCode) = osproc.execCmdEx("git pull origin " & branch.strip) + if exitCode != 0: + error c, pkg, output + else: + message(c, "[Hint] ", pkg, "successfully updated") + else: + error c, pkg, "could not fetch current branch name" + proc main = var action = "" var args: seq[string] = @[] @@ -525,6 +550,8 @@ proc main = of "search", "list": updatePackages(c) search getPackages(c.workspace), args + of "update": + updateWorkspace(c, if args.len == 0: "" else: args[0]) of "extract": singleArg() if fileExists(args[0]):